diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..3476f8d --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,532 @@ +----------------------------------------------------------------------------- + + --- CAEN SpA - Software Division --- + +----------------------------------------------------------------------------- + + CAEN Dig2 + + Changelog. + +----------------------------------------------------------------------------- + + +v1.6.1 (17/06/2024) +------------------- + +Fixes: +- Revert the fix on v1.6.0 about "disabling send operations right after the + connection" because, at least on Windows, makes the operating system to + close the communication socket after 2 minutes of inactivity +- Minor performance improvement on DPP-PSD decode. + + +v1.6.0 (10/06/2024) +------------------- + +New features: +- Support for 10G UDP. +- Python demo for Scope and DPP-PSD. +- New demo with support for multiple board with synchronization. +- Add support for connection with dig2://caen.internal/usb?pid=PID as + alternative to dig2://caen.internal/usb/PID, for consistency with the + CAEN Dig1 library. +- The maximum socket receive buffer of the hardware endpoint socket, + can now be adjusted using the rcvbuf query parameter in the connection + URL (e.g. dig2://192.0.2.1/?rcvbuf=65536). The value, in bytes, is used + as argument for setsockopt with SO_RCVBUF. The setting applies to every + hardware endpoints: Raw, RawUDP and OpenData. +- On Linux, autoconf adds -std=c++20 if supported by the compiler. +- Add build tests for Clang 15, 16, 17 and 18, and for GCC 13 and 14. +- Add build tests for multiple versions of Boost (1.67, 1.74 and 1.83) +- Windows build environment updated: MSVC2019 16.11.35 and Boost 1.84. + +Fixes: +- Fix value of REAL_TIME_NS, LIVE_TIME_NS and DEAD_TIME_NS of stats endpoint + on DPP-PSD of 2730. +- Add support for keep alive packets on main communication socket to + mitigate rare missing data from digitizer, happening expecially on + commands that clear data, like ClearData, ArmAcquisition and Reset. + By default the interval is set at 4 seconds but can be adjusted using + "keepalive" query on the URL (e.g. dig2://192.0.2.1/?keepalive=10). + It can also be disabled by setting keepalive=0. +- Increase GateOffsetS value on DPP-PSD demo, to be compatible with 2730. +- Application layer message header is now always zero-initialized. +- Endpoint communication improved by disabling send operations right after + the connection, since the client does not send data on that socket. + + +v1.5.10 (05/09/2023) +------------------- + +New features: +- Support for renamed parameters in new DPP-ZLE CUP releases. + +Fixes: +- Removed bad code from Scope demo, introduced on v1.5.9. + + +v1.5.9 (31/07/2023) +------------------- + +New features: +- TIMESTAMP_NS decoded field of DPP-PHA and DPP-PSD endpoints now supports + the data format of 2730, where the LSB corresponds to 2 ns instead of 8 + ns of 2740/2745. The field now is internally stored as DOUBLE, while + previously was U64. Assuming sampling period is a power of 2 when + expressed in nanoseconds, there are no changes in the user experience + because IEEE 754 double-precision floating point can store exactly + integers up to 2^53. Since digitizers pass timestamps in 48 bits, any + value multiplied by a power of 2 (between -1022 and 1023, of course) is + always stored exactly in a IEEE 754 double-precision floating point + value. +- Improved error messages generated by CAEN_FELib_SetReadDataFormat. +- Add demo projects to docdir on Linux package. When using the default + Autoconf prefix, they can be found on /usr/local/share/doc/caen_dig2. +- Minor improvements to demo project. Removed WaveResolution from DPP-PHA and + DPP-PSD demo because deprecated, to be replaced with a new parameter + WaveDownsamplingRate available in the next CUP releases. On DPP-ZLE demo, + now all channels are attached to ITLA by default (previously, only + channel 0 was used). +- On demo, tinycthread replaced by c11thread from John Tsiombikas and Oliver + Old. This change is transparent to the user and provides a much more + robust implementation of C11 threads on Windows. + +Changes: +- When using CAEN_FELib_ReadData/CAEN_FELib_HasData with zero timeout, the + CAEN Dig2 library internally was forcing timeout to 1 ms. Now this + behavior has been removed, and zero timeout means no wait at all. Note + that the readout is asynchronous on all the endpoints: a call to + CAEN_FELib_ReadData/CAEN_FELib_HasData does not directly generate + communication with the devices, but only checks in internal library + buffers. + +Fixes: +- The check for calls to CAEN_FELib_ReadData/CAEN_FELib_HasData pending on + other threads on the same endpoint has been improved. + + +v1.5.8 (12/04/2023) +------------------- + +Fixes: +- DPP-ZLE demo made almost identical to Scope demo, using reconstructed + instead of raw waveforms. +- Fix minor memory leak on Scope demo. + + +v1.5.7 (16/03/2023) +------------------- + +New features: +- New reserved URL host caen.internal to help some special connections: + - USB: dig2://caen.internal/usb/PID (kept legacy support for dig2://usb:PID) + - OpenARM: dig2://caen.internal/openarm (just an alias for 172.17.0.1) +- Binaries for aarch64 architecture are now provided by CAEN to help deploy + on OpenARM. +- Add plot on demo Scope. +- Windows build environment updated: MSVC2019 16.11.23 and Boost 1.81. + +Fixes: +- Fix build with Boost version from 1.71 to 1.74. +- Fix a runtime check on raw endpoint implementation. +- Fix plot on DPP-ZLE demo. + + +v1.5.6 (23/12/2022) +------------------- + +Fixes: +- Demo MSVC2015 projects Target Platform Version reverted to "10.0.16299.0" + because "10.0" introduced on v1.5.5 is never valid. + + +v1.5.5 (22/12/2022) +------------------- + +New features: +- Support for group level parameters, required by CUP running the Back-end + Server version >= v1.4.0 (requires CAEN FELib >= v1.2.3). + +Fixes: +- Fix critical issue in DPP-ZLE decode. + +Changes: +- Demo released under the public domain (MIT No Attribution license). +- Demo MSVC2015 projects now point to a generic 10.0 SDK instead of to + specific version 10.0.16299.0. + + +v1.5.4 (07/12/2022) +------------------- + +New features: +- Support for new DPP-ZLE CUPs. +- json to 3.11.2. +- Windows build environment updated: MSVC2019 16.11.17. + +Fixes: +- Documentation and copyright notice updated. +- Major update of DPP-ZLE demo. +- Other minor fixes on other demo projects. + +Changes: +- Remove support for legacy endpoint names on preliminary CUPs. + + +v1.5.3 (10/06/2022) +------------------- + +New features: +- Support for counter info word of statistics events of DPP-PHA and DPP-PSD. + The information can be accessed using two new fields TRIGGER_CNT and + SAVED_EVENT_CNT on respective stats endpoints. +- Memory usage reduced when using decoded endpoint with wave trigger source + disabled for all channels. In case a source is set during run, memory + allocation will be done later, at cost of a minimal performance penalty. + The feature applies to DPP-PHA and DPP-PSD. It is worth mentioning that + that the same performance penalty is payed also when starting an + acquisition without any enabled channel, enabling a channel during the run. + This applies to DPP-PHA, DPP-PSD and Open DPP since the first version of + this library. +- spdlog to 1.10.0. +- Added build tests for Clang 11, 12, 13 and 14, and for GCC 12. + +Fixes: +- Fix regression on DPP-ZLE decode introduced on v1.5.2. +- Fix "w" command to wave plot, failing on events without waveform. This applies + to DPP-PHA and DPP-PSD demo. +- Possible undefined behavior and SIGBUS when running on 32-bit ARM due to + memory access with bad alignment. + + +v1.5.2 (19/05/2022) +------------------- + +New features: +- New field SAMPLES_OVERLAPPED available on Scope events (scalar 3-bit unsigned + integer). +- New fields FLUSH (scalar boolean) and AGGREGATE_COUNTER (scalar 24-bit unsigned + integer) available on DPP-PHA, DPP-PSD, Open DPP and DPP-ZLE events. Their + values are shared by all events in the aggregate, like the existing BOARD_FAIL. + Even if not carrying information about the event itself, they can be used for + advanced statistics and diagnostics. On DPP-ZLE, since events could be made + of more aggregates, FLUSH is the or of all participating aggregates fields, + just like BOARD_FAIL, while AGGREGATE_COUNTER is the counter of the first + aggregate. +- Decoded endpoint performance improvements. The feature applies to all types + of endpoints, but it is expecially effective for DPP-PHA, DPP-PSD and + Open DPP. +- Memory usage reduced when using decoded endpoint. +- Windows build environment updated: MSVC2019 16.11.14, Boost 1.79.0, Inno Setup + 6.2.1. + +Fixes: +- Fix build on big endian systems. + + +v1.5.1 (14/04/2022) +------------------- + +New features: +- Support for CDC interface on Linux, to achieve maximum speed on USB3 also + after a regression on RNDIS introduced on recent kernel versions. + +Fixes: +- Improve robustness of decode of DPP-PHA and DPP-PSD special events: in case + of hypotetical events in which the third word was not the last word, the + decode did not complete the event leaving the buffer pointer not aligned + to the beginning of the next event. +- More exhaustive compile time checks on the supported compilers to improve + performance. +- Use fastest integer types provided by cstdint when appropriate. + + +v1.5.0 (29/03/2022) +------------------- + +New features: +- Support for CAEN_FELib_HasData (requires CAEN FELib v1.2.0). +- Memory usage reduced when using decoded endpoint and record length + lesser than the maximum record length allowed by the firmware. The + feature applies to DPP-PHA and DPP-PSD firmwares. +- Memory usage reduced when using raw endpoint. The feature applies to + Scope, DPP-PHA, DPP-PSD and DPP-ZLE firmwares. +- Decoder thread now is launched at arm only if decoded endpoint is + active, then it is closed at clear or at close. +- In case CAEN_FELib_ReadData now returns an error if it is called while + being called on the same endpoint by another thread. +- Support for single word DPP events. The feature applies to DPP-PHA, + DPP-PSD and Open DPP. +- DPP-PSD demo. +- Debug logging information improved. + +Fixes: +- Fix deadlock when clearing data after a run with events larger than + 2^26 bytes. The fix applies to Scope firmware. +- Fix a rare deadlock, introduced with v1.4.2, that may occur when + clearing data. +- The patch to properly close the library on Windows, when all devices + have not been closed, now is much more robust. +- Fix a buffer overflow occurring when disabling channels or reducing + record length after an acquisition with data still to be read from + the digitizer. The fix applies to Scope firmware. +- Fix proper connection closure at exit. This fixes also a crash in the + demo when using USB, that may result either in an undefined behavior + of in an assertion failure (only on Linux if compiled without + --disable-assert). +- Fix build with SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE defined on + preprocessor. +- Fixed support for literal IPv6 addresses in URL (RFC 2732) on Linux. +- Fix decode of additional headers of special events (start and stop), + even if the information is not used on the decode process. +- Fix build on clang 3.8 with Boost < 1.71 (broken since v1.4.1) +- Revert JSON for Modern C++ to v3.10.2 to fix build on clang 3.9 + (broken since v1.4.3). +- Add checks for data consistency, also when assertions have been + disabled (i.e. on Windows release builds and using --disable-assert + on autoconf). In case of a critical error, logger (if enabled) + prints a critical level message and then std::terminate is called. +- Improved robustness of decoded endpoint against data inconsistencies. +- DPP-ZLE decode performance improved. + + +v1.4.3 (07/02/2022) +------------------- + +New features: +- JSON for Modern C++ to version v3.10.5 + +Fixes: +- The correction of the clear mechanism introduced in version v1.4.2 was + not working properly when using raw endpoint. +- Autoconf configure script can be invoked also from other directories. + + +v1.4.2 (24/01/2022) +------------------- + +New features: +- Resource version properly set for Windows DLL, setting both file version + and product version fields to the library version. +- Performance improvements of the event decoding on Scope firmware. +- DPP-PSD support. +- Add N_EVENTS to raw endpoint to get the number of events in the blob. In + case of firmware using aggregate events (DPP firmwares) it returns the + number of aggregates. +- Add SPECIAL_EVENT field to Open DPP decoded endpoint. + +Fixes: +- Fix severe bug in the clear mechanism, usually detected when starting a + second acquisition, that was pretty common at high rate. It was + generating heap corruption with consequent application crashes. +- Add support for events with no enabled channel on Scope firmware, now + correctly passed to the user with all sizes on WAVEFORM_SIZE set to + zero and EVENT_SIZE to 24. +- Fix waveform decoding on big endian systems. +- Improve performance of CAEN_FELib_ReadData returning CAEN_FELib_Timeout + and CAEN_FELib_Stop. +- Fix a rare bug that might occour during debug. +- Microsoft Visual C++ Redistributable now installed with quiet flag on + Windows setup. +- Improve memory usage when arming a new run with reduced record length. + The fix applies to Scope and DPP-ZLE firmwares. +- Performance improvements of DPP-PHA decode on Linux for events with + waveform payload. + +Changes: +- On DPP-PHA and DPP-PSD decoded endpoints, now *_TYPE probe fields return + values, still as U8, that are common for both firmwares. See + dpp_probe_types.hpp for details. Integral values have been chosen to + keep backward compatibility with existing code using DPP-PHA. +- Remove useless stdout logger. + + +v1.4.1 (17/11/2021) +------------------- + +New features: +- Resource version properly set for Windows DLL. +- Various code documentation improvements. +- Performance improvements of the internal buffer resize during the + data acquisition using a custom `std::vector` allocator that performs + default initialization instead of value inizialization. +- Support of OpenData endpoint for OpenFPGA implementations. + +Fixes: +- Fixed library unload when program is closed before all connected deviced + have been manually disconnected with CAEN_FELib_Close(). +- Fix a rare bug that might occour on CAEN_FELib_ReadData() failures. + +Changes: +- Requires CAEN FELib v1.1.4 and its new type CAEN_FELib_NodeType_t that + replaces the deprecated CAEN_FELib_nodeType_t. +- Removed check for device already opened that returned error code + CAEN_FELib_DeviceAlreadyOpen, since it is legal to open twice the same + device if the second connection is a monitor connection. Furthermore, + the check for the device already opened was pretty weak, as based only + on the name used on the connection path, that could be not unique in + case of multiple DNS entries or IP used instead of hostname. + + +v1.4.0 (15/09/2021) +------------------- + +New features: +- Log level can be specified for each client using log_level in url query, + by default it is set to off. +- Support for BackEnd Server 1.3.0 and CAEN FELib 1.1.3, in particular for + the VGA node type support. +- Communication errors raise ::CAEN_FELib_CommunicationError error. + +Fixes: +- Fix value of _WIN32_WINNT macro used to build Boost.ASIO, now specifiying + correctly Windows 8.1. +- Linux package improved. +- Demo build fixed on Linux distributions not supporting C11 threads. + +Changes: +- Windows setup install DLL to %ProgramFiles%\CAEN\Digitizers\CAEN Dig2\bin + folder instead of [...]\lib. + + +v1.3.0 (16/06/2021) +------------------- + +New features: +- New statistics endpoint support for DPP-PHA at /endpoint/dpppha/stats, + currently supporting REAL_TIME, LIVE_TIME and DEAD_TIME (and respective + *_NS versions providing time in nanoseconds). +- DPP-ZLE demo. +- New endpoint data format types char ("CHAR"), ptrdiff_t ("PTRDIFF_T") and + long double ("LONG DOUBLE"). + +Fixes: +- Support serialization of LVDS and VGA (requires server version >= 1.2.0). +- -Wall added to Autoconf build. + + +v1.2.6 (14/05/2021) +------------------- + +New features: +- BOARD_FAIL field added to all DPP endpoints to get eventual fail status + when the event has been recorded (already supported by Scope endpoint). + +Fixes: +- Performance improvement of DPP-PHA and Open DPP. +- Workaround to avoid long compilation time with GCC due to GCC bug 71165. +- Fix RECORD_LENGTH field of DPP-ZLE that was scaled by a factor 4. +- Fix trivial bug on DPP-PHA demo. + +Changes: +- Type of DIGITAL_PROBE_* in default data format of DPP-PHA endpoint changed + from BOOL to U8; this should not break existing code using default data + format due to identical binary representation of bool and a uint8_t with + values 0 or 1. + + +v1.2.5 (03/05/2021) +------------------- + +New features: +- Demo projects largely improved. Plot added to DPP-PHA (gnuplot is included + in Windows, must be installed by the user on Linux). +- Support for DPP-ZLE. +- TIMESTAMP_NS field added to all endpoints to get timestamp in nanoseconds. + +Fixes: +- Performance of DPP-PHA decoded ReadData improved, expecially for high rate. +- Clear could hang forever when invoked in DPP-family firmwares. +- Fix rare segmentation fault when invoking Close very close to Open. + + +v1.2.4 (01/04/2021) +------------------- + +Fixes: +- Linux and Windows packages improved. +- Demo now can read board path from command arguments. +- Failed assertions invoke std::abort instead of std::terminate. +- Boost.ASIO targeting to Windows 8.1 (previously Windows 7). + + +v1.2.3 (26/03/2021) +------------------- + +New features: +- DPP-PHA demo working (no plotter). +- spdlog to 1.8.5. + +Fixes: +- Server version alignment check does not trigger on different patch level. + + +v1.2.2 (24/03/2021) +------------------- + +Fixes: +- Support for server version 1.1.3. + + +v1.2.1 (23/03/2021) +------------------- + +New featured: +- First tentative implementation of DPP-ZLE decode, still to be tested. +- Resources added to Windows DLL. + +Fixes: +- DPP-PHA readdata fixed in case of no waveform in the event +- DPP-PHA fake bit decode fixed. +- Connection after disconnection fixed by disabling automatic registration + of spglog loggers. + + +v1.2.0 (18/03/2021) +------------------- + +Breaking changes: +- New endpoint paths: + - Raw endpoint still at /endpoint/raw. + - Decoded endpoint at /endpoint/. + - /endpoint/raw/par/isdecoded moved to /endpoint/par/activeendpoint, with + allowed values raw or . + +New features: +- Support for GCC 5 with optional compliance to C++14: C++17 features used + only if available. +- Compile time reduced. +- DPP-PHA decode performance improvement. + +Fixes: +- Multiple connection fixed. + + +v1.1.0 (04/03/2021) +------------------- + +New features: +- GetDeviceTree implemented. +- Preliminary DPP-PHA support. +- Conformant URL support as Open argument. +- Monitor client passing monitor as URL query (e.g. dig2://192.0.2.1/?monitor). +- Log on file disabled by default (SPDLOG_LEVEL environmental variable can be + used to enable it). Furthermore, TRACE and DEBUG messages are not compiled by + default but can be enabled by defining SPDLOG_ACTTIVE_LEVEL=0 at compile time. + See spdlog documentation for details. + +Changes: +- Scope decoded endpoint renamed from /endpoint/raw/waveform /endpoint/raw/scope + (but the decoded endpoint paths will change again in a future release). +- EVENT_COUNTER renamed to TRIGGER_ID in Scope decode data format. +- HAS_WAVEFORM removed from Scope decode data format, as the same information + is retrievable from WAVEFORM_SIZE. +- Code is almost all C++14 conformant for compatibility with old compilers. + Standard will change in a future release. + + +v1.0.3 (21/01/2021) +------------------- + +First public release. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/COPYING.LESSER b/COPYING.LESSER new file mode 100644 index 0000000..0a04128 --- /dev/null +++ b/COPYING.LESSER @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..9d19196 --- /dev/null +++ b/INSTALL @@ -0,0 +1,54 @@ +----------------------------------------------------------------------------- + + --- CAEN SpA - Software Division --- + +----------------------------------------------------------------------------- + + CAEN Dig2 + + Install procedure on Linux. + +----------------------------------------------------------------------------- + + +Prerequisites +------------- + +- A compiler supporting C++14, C++17 or C++20. + The following compiler versions have been tested on x86_64: + - GCC >= 5 (up to version 14) + - clang >= 3.8 (up to version 18*) +- CAEN FELib >= 1.3.0 +- Boost C++ libraries (headers only, see build instructions). + The following Boost versions have been tested on x86_64: + - 1.67, 1.74, 1.83 + +*) versions >= 16 require Boost >= 1.81 + + +Install +------- + +In the extracted folder run + + $ ./configure --disable-assert + $ make + $ sudo make install + $ sudo ldconfig + + +Boost C++ libraries +------------------- + +The most recent distributions provides Boost >= 1.67.0 with their package managers. +If your Linux distribution provides an older version of Boost libraries, just download +the sources of Boost 1.67.0 from https://www.boost.org/users/history/version_1_67_0.html, +extract them in any folder, and run configure using the `--with-boost` flag. + +There is no need to compile Boost, as Boost shared libraries are not required at runtime. + +For example if you have extracted it in `/opt/boost_1_67_0`, execute: + + $ ./configure --disable-assert --with-boost="/opt/boost_1_67_0" + +Then, just make as usual. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..0c8e57c --- /dev/null +++ b/Makefile.am @@ -0,0 +1,42 @@ +# Copyright (C) 2020-2023 CAEN SpA +# +# This file is part of the CAEN Dig2 Library. +# +# The CAEN Dig2 Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# The CAEN Dig2 Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the CAEN Dig2 Library; if not, see +# https://www.gnu.org/licenses/. +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = src +dist_noinst_HEADERS = \ + include \ + json/include \ + spdlog/include \ + backend-server/include/server_definitions.hpp \ + backend-server/include/json +EXTRA_DIST = \ + COPYING \ + COPYING.LESSER \ + INSTALL \ + README_LINUX.txt \ + CHANGELOG \ + json/LICENSE.MIT \ + json/README.md \ + spdlog/LICENSE \ + spdlog/README.md \ + demo +dig2docdir = $(docdir) +dist_dig2doc_DATA = \ + doc/demo.tar.gz diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..d2daa0c --- /dev/null +++ b/Makefile.in @@ -0,0 +1,912 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Copyright (C) 2020-2023 CAEN SpA +# +# This file is part of the CAEN Dig2 Library. +# +# The CAEN Dig2 Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# The CAEN Dig2 Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the CAEN Dig2 Library; if not, see +# https://www.gnu.org/licenses/. +# +# SPDX-License-Identifier: LGPL-3.0-or-later + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(dist_dig2doc_DATA) \ + $(dist_noinst_HEADERS) $(am__DIST_COMMON) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(dig2docdir)" +DATA = $(dist_dig2doc_DATA) +HEADERS = $(dist_noinst_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope distdir distdir-am dist dist-all distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +CSCOPE = cscope +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in COPYING COPYING.LESSER INSTALL \ + ar-lib compile config.guess config.sub install-sh ltmain.sh \ + missing +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +DIST_TARGETS = dist-gzip +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_LDFLAGS = @BOOST_LDFLAGS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_CXX14 = @HAVE_CXX14@ +HAVE_CXX17 = @HAVE_CXX17@ +HAVE_CXX20 = @HAVE_CXX20@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_CXX = @PTHREAD_CXX@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +ax_pthread_config = @ax_pthread_config@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = src +dist_noinst_HEADERS = \ + include \ + json/include \ + spdlog/include \ + backend-server/include/server_definitions.hpp \ + backend-server/include/json + +EXTRA_DIST = \ + COPYING \ + COPYING.LESSER \ + INSTALL \ + README_LINUX.txt \ + CHANGELOG \ + json/LICENSE.MIT \ + json/README.md \ + spdlog/LICENSE \ + spdlog/README.md \ + demo + +dig2docdir = $(docdir) +dist_dig2doc_DATA = \ + doc/demo.tar.gz + +all: all-recursive + +.SUFFIXES: +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt +install-dist_dig2docDATA: $(dist_dig2doc_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_dig2doc_DATA)'; test -n "$(dig2docdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(dig2docdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(dig2docdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dig2docdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(dig2docdir)" || exit $$?; \ + done + +uninstall-dist_dig2docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_dig2doc_DATA)'; test -n "$(dig2docdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(dig2docdir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(dig2docdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-dist_dig2docDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-dist_dig2docDATA + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--refresh check check-am clean clean-cscope clean-generic \ + clean-libtool cscope cscopelist-am ctags ctags-am dist \ + dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ + dist-xz dist-zip distcheck distclean distclean-generic \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-dist_dig2docDATA install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-dist_dig2docDATA + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/README_LINUX.txt b/README_LINUX.txt new file mode 100644 index 0000000..97b3cd9 --- /dev/null +++ b/README_LINUX.txt @@ -0,0 +1,74 @@ +----------------------------------------------------------------------------- + + --- CAEN SpA - Software Division --- + +----------------------------------------------------------------------------- + + CAEN Dig2 Library + + Readme for Linux. + +----------------------------------------------------------------------------- + + +Copyright notice +---------------- + +Copyright (C) 2020-2023 CAEN SpA + +The CAEN Dig2 Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +The CAEN Dig2 Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License along +with the CAEN Dig2 Library; if not, see https://www.gnu.org/licenses/. + +The license applies to the CAEN Dig2 Library source as a whole, though individual +source files can have a different license which is required to be compatible +with the GNU Lesser General Public Library, version 3. You may find more details +on the Credits section of this file. + + +Support +------- + +For technical support, go to https://www.caen.it/mycaen/support/ (login and +MyCAEN+ account required). + +If you don't have an account or want to update your old one, find the instructions +at https://www.caen.it/support-services/getting-started-with-mycaen-portal/. + + +Content +------- + +Library : Source code is provided in this package. Build and install instructions can be found on INSTALL. +Demo : Demo projects with Makefile are deployed in the demo folder of this package. + + +Prerequisites +------------- + +- See INSTALL. + + +Credits +------- + +The CAEN Dig2 Library is made possible by other third part open source software. + +JSON for Modern C++: +- Website: https://github.com/nlohmann/json +- License: MIT License +- Copyright: Copyright 2013-2022 Niels Lohmann + +spdlog, a very fast, header-only/compiled, C++ logging library: +- Website: https://github.com/gabime/spdlog +- License: MIT license +- Copyright: Copyright 2016 Gabi Melman diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..96f3b1e --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,2695 @@ +# generated automatically by aclocal 1.16.1 -*- Autoconf -*- + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +# ============================================================================ +# https://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# For every FLAG1, FLAG2 it is checked whether the compiler works with the +# flag. If it does, the flag is added FLAGS-VARIABLE +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. During the check the flag is always added to the +# current language's flags. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: This macro depends on the AX_APPEND_FLAG and +# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with +# AX_APPEND_LINK_FLAGS. +# +# LICENSE +# +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 6 + +AC_DEFUN([AX_APPEND_COMPILE_FLAGS], +[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG]) +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +for flag in $1; do + AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4]) +done +])dnl AX_APPEND_COMPILE_FLAGS + +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_append_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) +# +# DESCRIPTION +# +# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space +# added in between. +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains +# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly +# FLAG. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 7 + +AC_DEFUN([AX_APPEND_FLAG], +[dnl +AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF +AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) +AS_VAR_SET_IF(FLAGS,[ + AS_CASE([" AS_VAR_GET(FLAGS) "], + [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], + [ + AS_VAR_APPEND(FLAGS,[" $1"]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) + ], + [ + AS_VAR_SET(FLAGS,[$1]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) +AS_VAR_POPDEF([FLAGS])dnl +])dnl AX_APPEND_FLAG + +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_append_link_flags.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# For every FLAG1, FLAG2 it is checked whether the linker works with the +# flag. If it does, the flag is added FLAGS-VARIABLE +# +# If FLAGS-VARIABLE is not specified, the linker's flags (LDFLAGS) is +# used. During the check the flag is always added to the linker's flags. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG. +# Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS. +# +# LICENSE +# +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 6 + +AC_DEFUN([AX_APPEND_LINK_FLAGS], +[AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +for flag in $1; do + AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3], [$4]) +done +])dnl AX_APPEND_LINK_FLAGS + +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_boost_base.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# DESCRIPTION +# +# Test for the Boost C++ libraries of a particular version (or newer) +# +# If no path to the installed boost library is given the macro searchs +# under /usr, /usr/local, /opt and /opt/local and evaluates the +# $BOOST_ROOT environment variable. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS) +# +# And sets: +# +# HAVE_BOOST +# +# LICENSE +# +# Copyright (c) 2008 Thomas Porschberg +# Copyright (c) 2009 Peter Adolphs +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 43 + +# example boost program (need to pass version) +m4_define([_AX_BOOST_BASE_PROGRAM], + [AC_LANG_PROGRAM([[ +#include +]],[[ +(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))])); +]])]) + +AC_DEFUN([AX_BOOST_BASE], +[ +AC_ARG_WITH([boost], + [AS_HELP_STRING([--with-boost@<:@=ARG@:>@], + [use Boost library from a standard location (ARG=yes), + from the specified location (ARG=), + or disable it (ARG=no) + @<:@ARG=yes@:>@ ])], + [ + AS_CASE([$withval], + [no],[want_boost="no";_AX_BOOST_BASE_boost_path=""], + [yes],[want_boost="yes";_AX_BOOST_BASE_boost_path=""], + [want_boost="yes";_AX_BOOST_BASE_boost_path="$withval"]) + ], + [want_boost="yes"]) + + +AC_ARG_WITH([boost-libdir], + [AS_HELP_STRING([--with-boost-libdir=LIB_DIR], + [Force given directory for boost libraries. + Note that this will override library path detection, + so use this parameter only if default library detection fails + and you know exactly where your boost libraries are located.])], + [ + AS_IF([test -d "$withval"], + [_AX_BOOST_BASE_boost_lib_path="$withval"], + [AC_MSG_ERROR([--with-boost-libdir expected directory name])]) + ], + [_AX_BOOST_BASE_boost_lib_path=""]) + +BOOST_LDFLAGS="" +BOOST_CPPFLAGS="" +AS_IF([test "x$want_boost" = "xyes"], + [_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])]) +AC_SUBST(BOOST_CPPFLAGS) +AC_SUBST(BOOST_LDFLAGS) +]) + + +# convert a version string in $2 to numeric and affect to polymorphic var $1 +AC_DEFUN([_AX_BOOST_BASE_TONUMERICVERSION],[ + AS_IF([test "x$2" = "x"],[_AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0"],[_AX_BOOST_BASE_TONUMERICVERSION_req="$2"]) + _AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\.[[0-9]]*\)'` + _AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\)'` + AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"], + [AC_MSG_ERROR([You should at least specify libboost major version])]) + _AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.\([[0-9]]*\)'` + AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"], + [_AX_BOOST_BASE_TONUMERICVERSION_req_minor="0"]) + _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + AS_IF([test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"], + [_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0"]) + _AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor` + AS_VAR_SET($1,$_AX_BOOST_BASE_TONUMERICVERSION_RET) +]) + +dnl Run the detection of boost should be run only if $want_boost +AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ + _AX_BOOST_BASE_TONUMERICVERSION(WANT_BOOST_VERSION,[$1]) + succeeded=no + + + AC_REQUIRE([AC_CANONICAL_HOST]) + dnl On 64-bit systems check for system libraries in both lib64 and lib. + dnl The former is specified by FHS, but e.g. Debian does not adhere to + dnl this (as it rises problems for generic multi-arch support). + dnl The last entry in the list is chosen by default when no libraries + dnl are found, e.g. when only header-only libraries are installed! + AS_CASE([${host_cpu}], + [x86_64],[libsubdirs="lib64 libx32 lib lib64"], + [ppc64|s390x|sparc64|aarch64|ppc64le],[libsubdirs="lib64 lib lib64"], + [libsubdirs="lib"] + ) + + dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give + dnl them priority over the other paths since, if libs are found there, they + dnl are almost assuredly the ones desired. + AS_CASE([${host_cpu}], + [i?86],[multiarch_libsubdir="lib/i386-${host_os}"], + [multiarch_libsubdir="lib/${host_cpu}-${host_os}"] + ) + + dnl first we check the system location for boost libraries + dnl this location ist chosen if boost libraries are installed with the --layout=system option + dnl or if you install boost with RPM + AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[ + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"]) + AS_IF([test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"],[ + AC_MSG_RESULT([yes]) + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include" + for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"]) + AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[ + AC_MSG_RESULT([yes]) + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"; + break; + ], + [AC_MSG_RESULT([no])]) + done],[ + AC_MSG_RESULT([no])]) + ],[ + if test X"$cross_compiling" = Xyes; then + search_libsubdirs=$multiarch_libsubdir + else + search_libsubdirs="$multiarch_libsubdir $libsubdirs" + fi + for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then + for libsubdir in $search_libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir" + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include" + break; + fi + done + ]) + + dnl overwrite ld flags if we have required special directory with + dnl --with-boost-libdir parameter + AS_IF([test "x$_AX_BOOST_BASE_boost_lib_path" != "x"], + [BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path"]) + + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION)]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_REQUIRE([AC_PROG_CXX]) + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[ + ]) + AC_LANG_POP([C++]) + + + + dnl if we found no boost with system layout we search for boost libraries + dnl built and installed without the --layout=system option or for a staged(not installed) version + if test "x$succeeded" != "xyes" ; then + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + BOOST_CPPFLAGS= + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + BOOST_LDFLAGS= + fi + _version=0 + if test -n "$_AX_BOOST_BASE_boost_path" ; then + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "x$V_CHECK" = "x1" ; then + _version=$_version_tmp + fi + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE" + done + dnl if nothing found search for layout used in Windows distributions + if test -z "$BOOST_CPPFLAGS"; then + if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path" + fi + fi + dnl if we found something and BOOST_LDFLAGS was unset before + dnl (because "$_AX_BOOST_BASE_boost_lib_path" = ""), set it here. + if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then + for libsubdir in $libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir" + fi + fi + else + if test "x$cross_compiling" != "xyes" ; then + for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "x$V_CHECK" = "x1" ; then + _version=$_version_tmp + best_path=$_AX_BOOST_BASE_boost_path + fi + done + fi + done + + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + for libsubdir in $libsubdirs ; do + if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$best_path/$libsubdir" + fi + fi + + if test -n "$BOOST_ROOT" ; then + for libsubdir in $libsubdirs ; do + if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then + version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` + stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` + stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` + V_CHECK=`expr $stage_version_shorten \>\= $_version` + if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) + BOOST_CPPFLAGS="-I$BOOST_ROOT" + BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir" + fi + fi + fi + fi + + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[ + ]) + AC_LANG_POP([C++]) + fi + + if test "x$succeeded" != "xyes" ; then + if test "x$_version" = "x0" ; then + AC_MSG_NOTICE([[We could not detect the boost libraries (version $1 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) + else + AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) + fi + # execute ACTION-IF-NOT-FOUND (if present): + ifelse([$3], , :, [$3]) + else + AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) + # execute ACTION-IF-FOUND (if present): + ifelse([$2], , :, [$2]) + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + +]) + +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 5 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS + +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the linker or gives an error. +# (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 5 + +AC_DEFUN([AX_CHECK_LINK_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ + ax_check_save_flags=$LDFLAGS + LDFLAGS="$LDFLAGS $4 $1" + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + LDFLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_LINK_FLAGS + +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compare_version.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# This macro compares two version strings. Due to the various number of +# minor-version numbers that can exist, and the fact that string +# comparisons are not compatible with numeric comparisons, this is not +# necessarily trivial to do in a autoconf script. This macro makes doing +# these comparisons easy. +# +# The six basic comparisons are available, as well as checking equality +# limited to a certain number of minor-version levels. +# +# The operator OP determines what type of comparison to do, and can be one +# of: +# +# eq - equal (test A == B) +# ne - not equal (test A != B) +# le - less than or equal (test A <= B) +# ge - greater than or equal (test A >= B) +# lt - less than (test A < B) +# gt - greater than (test A > B) +# +# Additionally, the eq and ne operator can have a number after it to limit +# the test to that number of minor versions. +# +# eq0 - equal up to the length of the shorter version +# ne0 - not equal up to the length of the shorter version +# eqN - equal up to N sub-version levels +# neN - not equal up to N sub-version levels +# +# When the condition is true, shell commands ACTION-IF-TRUE are run, +# otherwise shell commands ACTION-IF-FALSE are run. The environment +# variable 'ax_compare_version' is always set to either 'true' or 'false' +# as well. +# +# Examples: +# +# AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) +# +# would both be true. +# +# AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) +# +# would both be false. +# +# AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) +# +# would be true because it is only comparing two minor versions. +# +# AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) +# +# would be true because it is only comparing the lesser number of minor +# versions of the two values. +# +# Note: The characters that separate the version numbers do not matter. An +# empty string is the same as version 0. OP is evaluated by autoconf, not +# configure, so must be a string, not a variable. +# +# The author would like to acknowledge Guido Draheim whose advice about +# the m4_case and m4_ifvaln functions make this macro only include the +# portions necessary to perform the specific comparison specified by the +# OP argument in the final configure script. +# +# LICENSE +# +# Copyright (c) 2008 Tim Toolan +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 13 + +dnl ######################################################################### +AC_DEFUN([AX_COMPARE_VERSION], [ + AC_REQUIRE([AC_PROG_AWK]) + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + AS_VAR_PUSHDEF([A],[ax_compare_version_A]) + A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + AS_VAR_PUSHDEF([B],[ax_compare_version_B]) + B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary + dnl # then the first line is used to determine if the condition is true. + dnl # The sed right after the echo is to remove any indented white space. + m4_case(m4_tolower($2), + [lt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [gt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [le],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ], + [ge],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ],[ + dnl Split the operator from the subversion count if present. + m4_bmatch(m4_substr($2,2), + [0],[ + # A count of zero means use the length of the shorter version. + # Determine the number of characters in A and B. + ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` + ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` + + # Set A to no more than B's length and B to no more than A's length. + A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` + B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` + ], + [[0-9]+],[ + # A count greater than zero means use only that many subversions + A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + ], + [.+],[ + AC_WARNING( + [invalid OP numeric parameter: $2]) + ],[]) + + # Pad zeros at end of numbers to make same length. + ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" + B="$B`echo $A | sed 's/./0/g'`" + A="$ax_compare_version_tmp_A" + + # Check for equality or inequality as necessary. + m4_case(m4_tolower(m4_substr($2,0,2)), + [eq],[ + test "x$A" = "x$B" && ax_compare_version=true + ], + [ne],[ + test "x$A" != "x$B" && ax_compare_version=true + ],[ + AC_WARNING([invalid OP parameter: $2]) + ]) + ]) + + AS_VAR_POPDEF([A])dnl + AS_VAR_POPDEF([B])dnl + + dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. + if test "$ax_compare_version" = "true" ; then + m4_ifvaln([$4],[$4],[:])dnl + m4_ifvaln([$5],[else $5])dnl + fi +]) dnl AX_COMPARE_VERSION + +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPILER_VENDOR +# +# DESCRIPTION +# +# Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun, +# hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft, +# watcom, etc. The vendor is returned in the cache variable +# $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2008 Matteo Frigo +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 17 + +AC_DEFUN([AX_COMPILER_VENDOR], +[AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, + dnl Please add if possible support to ax_compiler_version.m4 + [# note: don't check for gcc first since some other compilers define __GNUC__ + vendors="intel: __ICC,__ECC,__INTEL_COMPILER + ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__ + pathscale: __PATHCC__,__PATHSCALE__ + clang: __clang__ + cray: _CRAYC + fujitsu: __FUJITSU + sdcc: SDCC, __SDCC + gnu: __GNUC__ + sun: __SUNPRO_C,__SUNPRO_CC + hp: __HP_cc,__HP_aCC + dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER + borland: __BORLANDC__,__CODEGEARC__,__TURBOC__ + comeau: __COMO__ + kai: __KCC + lcc: __LCC__ + sgi: __sgi,sgi + microsoft: _MSC_VER + metrowerks: __MWERKS__ + watcom: __WATCOMC__ + portland: __PGI + tcc: __TINYC__ + unknown: UNKNOWN" + for ventest in $vendors; do + case $ventest in + *:) vendor=$ventest; continue ;; + *) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;; + esac + AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ + #if !($vencpp) + thisisanerror; + #endif + ])], [break]) + done + ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1` + ]) +]) + +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compiler_version.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPILER_VERSION +# +# DESCRIPTION +# +# This macro retrieves the compiler version and returns it in the cache +# variable $ax_cv_c_compiler_version for C and $ax_cv_cxx_compiler_version +# for C++. +# +# Version is returned as epoch:major.minor.patchversion +# +# Epoch is used in order to have an increasing version number in case of +# marketing change. +# +# Epoch use: * borland compiler use chronologically 0turboc for turboc +# era, +# +# 1borlanc BORLANDC++ before 5, 2cppbuilder for cppbuilder era, +# 3borlancpp for return of BORLANDC++ (after version 5.5), +# 4cppbuilder for cppbuilder with year version, +# and 5xe for XE era. +# +# An empty string is returned otherwise. +# +# LICENSE +# +# Copyright (c) 2014 Bastien ROUCARIES +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 12 + +# for intel +AC_DEFUN([_AX_COMPILER_VERSION_INTEL], + [ dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [__INTEL_COMPILER/100],, + AC_MSG_FAILURE([[[$0]] unknown intel compiler version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [(__INTEL_COMPILER%100)/10],, + AC_MSG_FAILURE([[[$0]] unknown intel compiler version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [(__INTEL_COMPILER%10)],, + AC_MSG_FAILURE([[[$0]] unknown intel compiler version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# for IBM +AC_DEFUN([_AX_COMPILER_VERSION_IBM], + [ dnl + dnl check between z/OS C/C++ and XL C/C++ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([], + [ + #if defined(__COMPILER_VER__) + choke me; + #endif + ])], + [ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [__xlC__/100],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler major version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [__xlC__%100],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__xlC_ver__/0x100],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_build, + [__xlC_ver__%0x100],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler build version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_build" + ], + [ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__xlC__%1000],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [(__xlC__/10000)%10],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [(__xlC__/100000)%10],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) +]) + +# for pathscale +AC_DEFUN([_AX_COMPILER_VERSION_PATHSCALE],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + __PATHCC__,, + AC_MSG_FAILURE([[[$0]] unknown pathscale major])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + __PATHCC_MINOR__,, + AC_MSG_FAILURE([[[$0]] unknown pathscale minor])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__PATHCC_PATCHLEVEL__],, + AC_MSG_FAILURE([[[$0]] unknown pathscale patch level])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# for clang +AC_DEFUN([_AX_COMPILER_VERSION_CLANG],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + __clang_major__,, + AC_MSG_FAILURE([[[$0]] unknown clang major])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + __clang_minor__,, + AC_MSG_FAILURE([[[$0]] unknown clang minor])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__clang_patchlevel__],,0) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# for crayc +AC_DEFUN([_AX_COMPILER_VERSION_CRAY],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + _RELEASE,, + AC_MSG_FAILURE([[[$0]] unknown crayc release])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + _RELEASE_MINOR,, + AC_MSG_FAILURE([[[$0]] unknown crayc minor])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor" + ]) + +# for fujitsu +AC_DEFUN([_AX_COMPILER_VERSION_FUJITSU],[ + AC_COMPUTE_INT(ax_cv_[]_AC_LANG_ABBREV[]_compiler_version, + __FCC_VERSION,, + AC_MSG_FAILURE([[[$0]]unknown fujitsu release])) + ]) + +# for GNU +AC_DEFUN([_AX_COMPILER_VERSION_GNU],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + __GNUC__,, + AC_MSG_FAILURE([[[$0]] unknown gcc major])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + __GNUC_MINOR__,, + AC_MSG_FAILURE([[[$0]] unknown gcc minor])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__GNUC_PATCHLEVEL__],, + AC_MSG_FAILURE([[[$0]] unknown gcc patch level])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# For sun +AC_DEFUN([_AX_COMPILER_VERSION_SUN],[ + m4_define([_AX_COMPILER_VERSION_SUN_NUMBER], + [ + #if defined(__SUNPRO_CC) + __SUNPRO_CC + #else + __SUNPRO_C + #endif + ]) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_until59, + !!(_AX_COMPILER_VERSION_SUN_NUMBER < 0x1000),, + AC_MSG_FAILURE([[[$0]] unknown sun release version])) + AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_until59" = X1], + [dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + _AX_COMPILER_VERSION_SUN_NUMBER % 0x10,, + AC_MSG_FAILURE([[[$0]] unknown sun patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + (_AX_COMPILER_VERSION_SUN_NUMBER / 0x10) % 0x10,, + AC_MSG_FAILURE([[[$0]] unknown sun minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (_AX_COMPILER_VERSION_SUN_NUMBER / 0x100),, + AC_MSG_FAILURE([[[$0]] unknown sun major version])) + ], + [dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + _AX_COMPILER_VERSION_SUN_NUMBER % 0x10,, + AC_MSG_FAILURE([[[$0]] unknown sun patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + (_AX_COMPILER_VERSION_SUN_NUMBER / 0x100) % 0x100,, + AC_MSG_FAILURE([[[$0]] unknown sun minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (_AX_COMPILER_VERSION_SUN_NUMBER / 0x1000),, + AC_MSG_FAILURE([[[$0]] unknown sun major version])) + ]) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" +]) + +AC_DEFUN([_AX_COMPILER_VERSION_HP],[ + m4_define([_AX_COMPILER_VERSION_HP_NUMBER], + [ + #if defined(__HP_cc) + __HP_cc + #else + __HP_aCC + #endif + ]) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_untilA0121, + !!(_AX_COMPILER_VERSION_HP_NUMBER <= 1),, + AC_MSG_FAILURE([[[$0]] unknown hp release version])) + AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_untilA0121" = X1], + [dnl By default output last version with this behavior. + dnl it is so old + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="01.21.00" + ], + [dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + (_AX_COMPILER_VERSION_HP_NUMBER % 100),, + AC_MSG_FAILURE([[[$0]] unknown hp release version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + ((_AX_COMPILER_VERSION_HP_NUMBER / 100)%100),, + AC_MSG_FAILURE([[[$0]] unknown hp minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + ((_AX_COMPILER_VERSION_HP_NUMBER / 10000)%100),, + AC_MSG_FAILURE([[[$0]] unknown hp major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) +]) + +AC_DEFUN([_AX_COMPILER_VERSION_DEC],[dnl + m4_define([_AX_COMPILER_VERSION_DEC_NUMBER], + [ + #if defined(__DECC_VER) + __DECC_VER + #else + __DECCXX_VER + #endif + ]) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + (_AX_COMPILER_VERSION_DEC_NUMBER % 10000),, + AC_MSG_FAILURE([[[$0]] unknown dec release version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + ((_AX_COMPILER_VERSION_DEC_NUMBER / 100000UL)%100),, + AC_MSG_FAILURE([[[$0]] unknown dec minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + ((_AX_COMPILER_VERSION_DEC_NUMBER / 10000000UL)%100),, + AC_MSG_FAILURE([[[$0]] unknown dec major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# borland +AC_DEFUN([_AX_COMPILER_VERSION_BORLAND],[dnl + m4_define([_AX_COMPILER_VERSION_TURBOC_NUMBER], + [ + #if defined(__TURBOC__) + __TURBOC__ + #else + choke me + #endif + ]) + m4_define([_AX_COMPILER_VERSION_BORLANDC_NUMBER], + [ + #if defined(__BORLANDC__) + __BORLANDC__ + #else + __CODEGEARC__ + #endif + ]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM(, + _AX_COMPILER_VERSION_TURBOC_NUMBER)], + [dnl TURBOC + AC_COMPUTE_INT( + _ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw, + _AX_COMPILER_VERSION_TURBOC_NUMBER,, + AC_MSG_FAILURE([[[$0]] unknown turboc version])) + AS_IF( + [test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw -lt 661 || test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw -gt 1023], + [dnl compute normal version + AC_COMPUTE_INT( + _ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + _AX_COMPILER_VERSION_TURBOC_NUMBER % 0x100,, + AC_MSG_FAILURE([[[$0]] unknown turboc minor version])) + AC_COMPUTE_INT( + _ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (_AX_COMPILER_VERSION_TURBOC_NUMBER/0x100)%0x100,, + AC_MSG_FAILURE([[[$0]] unknown turboc major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor"], + [dnl special version + AS_CASE([$_ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw], + [661],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:1.00"], + [662],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:1.01"], + [663],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:2.00"], + [ + AC_MSG_WARN([[[$0]] unknown turboc version between 0x295 and 0x400 please report bug]) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="" + ]) + ]) + ], + # borlandc + [ + AC_COMPUTE_INT( + _ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw, + _AX_COMPILER_VERSION_BORLANDC_NUMBER,, + AC_MSG_FAILURE([[[$0]] unknown borlandc version])) + AS_CASE([$_ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw], + dnl BORLANDC++ before 5.5 + [512] ,[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:2.00"], + [1024],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:3.00"], + [1024],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:3.00"], + [1040],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:3.1"], + [1106],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:4.0"], + [1280],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:5.0"], + [1312],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:5.02"], + dnl C++ Builder era + [1328],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="2cppbuilder:3.0"], + [1344],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="2cppbuilder:4.0"], + dnl BORLANDC++ after 5.5 + [1360],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.5"], + [1361],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.51"], + [1378],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.6.4"], + dnl C++ Builder with year number + [1392],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2006"], + [1424],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2007"], + [1555],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2009"], + [1569],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2010"], + dnl XE version + [1584],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe"], + [1600],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe:2"], + [1616],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe:3"], + [1632],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe:4"], + [ + AC_MSG_WARN([[[$0]] Unknown borlandc compiler version $_ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw please report bug]) + ]) + ]) + ]) + +# COMO +AC_DEFUN([_AX_COMPILER_VERSION_COMEAU], + [ dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [__COMO_VERSION__%100],, + AC_MSG_FAILURE([[[$0]] unknown comeau compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [(__COMO_VERSION__/100)%10],, + AC_MSG_FAILURE([[[$0]] unknown comeau compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor" + ]) + +# KAI +AC_DEFUN([_AX_COMPILER_VERSION_KAI],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__KCC_VERSION%100],, + AC_MSG_FAILURE([[[$0]] unknown kay compiler patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [(__KCC_VERSION/100)%10],, + AC_MSG_FAILURE([[[$0]] unknown kay compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [(__KCC_VERSION/1000)%10],, + AC_MSG_FAILURE([[[$0]] unknown kay compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +dnl LCC +dnl LCC does not output version... + +# SGI +AC_DEFUN([_AX_COMPILER_VERSION_SGI],[ + m4_define([_AX_COMPILER_VERSION_SGI_NUMBER], + [ + #if defined(_COMPILER_VERSION) + _COMPILER_VERSION + #else + _SGI_COMPILER_VERSION + #endif + ]) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [_AX_COMPILER_VERSION_SGI_NUMBER%10],, + AC_MSG_FAILURE([[[$0]] unknown SGI compiler patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [(_AX_COMPILER_VERSION_SGI_NUMBER/10)%10],, + AC_MSG_FAILURE([[[$0]] unknown SGI compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [(_AX_COMPILER_VERSION_SGI_NUMBER/100)%10],, + AC_MSG_FAILURE([[[$0]] unknown SGI compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# microsoft +AC_DEFUN([_AX_COMPILER_VERSION_MICROSOFT],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + _MSC_VER%100,, + AC_MSG_FAILURE([[[$0]] unknown microsoft compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (_MSC_VER/100)%100,, + AC_MSG_FAILURE([[[$0]] unknown microsoft compiler major version])) + dnl could be overridden + _ax_[]_AC_LANG_ABBREV[]_compiler_version_patch=0 + _ax_[]_AC_LANG_ABBREV[]_compiler_version_build=0 + # special case for version 6 + AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major" = "X12"], + [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + _MSC_FULL_VER%1000,, + _ax_[]_AC_LANG_ABBREV[]_compiler_version_patch=0)]) + # for version 7 + AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major" = "X13"], + [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + _MSC_FULL_VER%1000,, + AC_MSG_FAILURE([[[$0]] unknown microsoft compiler patch version])) + ]) + # for version > 8 + AS_IF([test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_major -ge 14], + [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + _MSC_FULL_VER%10000,, + AC_MSG_FAILURE([[[$0]] unknown microsoft compiler patch version])) + ]) + AS_IF([test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_major -ge 15], + [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_build, + _MSC_BUILD,, + AC_MSG_FAILURE([[[$0]] unknown microsoft compiler build version])) + ]) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_build" + ]) + +# for metrowerks +AC_DEFUN([_AX_COMPILER_VERSION_METROWERKS],[dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + __MWERKS__%0x100,, + AC_MSG_FAILURE([[[$0]] unknown metrowerks compiler patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + (__MWERKS__/0x100)%0x10,, + AC_MSG_FAILURE([[[$0]] unknown metrowerks compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (__MWERKS__/0x1000)%0x10,, + AC_MSG_FAILURE([[[$0]] unknown metrowerks compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# for watcom +AC_DEFUN([_AX_COMPILER_VERSION_WATCOM],[dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + __WATCOMC__%100,, + AC_MSG_FAILURE([[[$0]] unknown watcom compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (__WATCOMC__/100)%100,, + AC_MSG_FAILURE([[[$0]] unknown watcom compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor" + ]) + +# for PGI +AC_DEFUN([_AX_COMPILER_VERSION_PORTLAND],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + __PGIC__,, + AC_MSG_FAILURE([[[$0]] unknown pgi major])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + __PGIC_MINOR__,, + AC_MSG_FAILURE([[[$0]] unknown pgi minor])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__PGIC_PATCHLEVEL__],, + AC_MSG_FAILURE([[[$0]] unknown pgi patch level])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# tcc +AC_DEFUN([_AX_COMPILER_VERSION_TCC],[ + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version=[`tcc -v | $SED 's/^[ ]*tcc[ ]\+version[ ]\+\([0-9.]\+\).*/\1/g'`] + ]) + +# for GNU +AC_DEFUN([_AX_COMPILER_VERSION_SDCC],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + /* avoid parse error with comments */ + #if(defined(__SDCC_VERSION_MAJOR)) + __SDCC_VERSION_MAJOR + #else + SDCC/100 + #endif + ,, + AC_MSG_FAILURE([[[$0]] unknown sdcc major])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + /* avoid parse error with comments */ + #if(defined(__SDCC_VERSION_MINOR)) + __SDCC_VERSION_MINOR + #else + (SDCC%100)/10 + #endif + ,, + AC_MSG_FAILURE([[[$0]] unknown sdcc minor])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [ + /* avoid parse error with comments */ + #if(defined(__SDCC_VERSION_PATCH)) + __SDCC_VERSION_PATCH + #elsif(defined(_SDCC_VERSION_PATCHLEVEL)) + __SDCC_VERSION_PATCHLEVEL + #else + SDCC%10 + #endif + ],, + AC_MSG_FAILURE([[[$0]] unknown sdcc patch level])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# main entry point +AC_DEFUN([AX_COMPILER_VERSION],[dnl + AC_REQUIRE([AX_COMPILER_VENDOR]) + AC_REQUIRE([AC_PROG_SED]) + AC_CACHE_CHECK([for _AC_LANG compiler version], + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version, + [ dnl + AS_CASE([$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor], + [intel],[_AX_COMPILER_VERSION_INTEL], + [ibm],[_AX_COMPILER_VERSION_IBM], + [pathscale],[_AX_COMPILER_VERSION_PATHSCALE], + [clang],[_AX_COMPILER_VERSION_CLANG], + [cray],[_AX_COMPILER_VERSION_CRAY], + [fujitsu],[_AX_COMPILER_VERSION_FUJITSU], + [gnu],[_AX_COMPILER_VERSION_GNU], + [sun],[_AX_COMPILER_VERSION_SUN], + [hp],[_AX_COMPILER_VERSION_HP], + [dec],[_AX_COMPILER_VERSION_DEC], + [borland],[_AX_COMPILER_VERSION_BORLAND], + [comeau],[_AX_COMPILER_VERSION_COMEAU], + [kai],[_AX_COMPILER_VERSION_KAI], + [sgi],[_AX_COMPILER_VERSION_SGI], + [microsoft],[_AX_COMPILER_VERSION_MICROSOFT], + [metrowerks],[_AX_COMPILER_VERSION_METROWERKS], + [watcom],[_AX_COMPILER_VERSION_WATCOM], + [portland],[_AX_COMPILER_VERSION_PORTLAND], + [tcc],[_AX_COMPILER_VERSION_TCC], + [sdcc],[_AX_COMPILER_VERSION_SDCC], + [ax_cv_[]_AC_LANG_ABBREV[]_compiler_version=""]) + ]) +]) + +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_require_defined.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_REQUIRE_DEFINED(MACRO) +# +# DESCRIPTION +# +# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have +# been defined and thus are available for use. This avoids random issues +# where a macro isn't expanded. Instead the configure script emits a +# non-fatal: +# +# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found +# +# It's like AC_REQUIRE except it doesn't expand the required macro. +# +# Here's an example: +# +# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +# +# LICENSE +# +# Copyright (c) 2014 Mike Frysinger +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 2 + +AC_DEFUN([AX_REQUIRE_DEFINED], [dnl + m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) +])dnl AX_REQUIRE_DEFINED + +# Copyright (C) 2002-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.16' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.16.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.16.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# Copyright (C) 2011-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_AR([ACT-IF-FAIL]) +# ------------------------- +# Try to determine the archiver interface, and trigger the ar-lib wrapper +# if it is needed. If the detection of archiver interface fails, run +# ACT-IF-FAIL (default is to abort configure with a proper error message). +AC_DEFUN([AM_PROG_AR], +[AC_BEFORE([$0], [LT_INIT])dnl +AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([ar-lib])dnl +AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) +: ${AR=ar} + +AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], + [AC_LANG_PUSH([C]) + am_cv_ar_interface=ar + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], + [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([am_ar_try]) + if test "$ac_status" -eq 0; then + am_cv_ar_interface=ar + else + am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([am_ar_try]) + if test "$ac_status" -eq 0; then + am_cv_ar_interface=lib + else + am_cv_ar_interface=unknown + fi + fi + rm -f conftest.lib libconftest.a + ]) + AC_LANG_POP([C])]) + +case $am_cv_ar_interface in +ar) + ;; +lib) + # Microsoft lib, so override with the ar-lib wrapper script. + # FIXME: It is wrong to rewrite AR. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__AR in this case, + # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something + # similar. + AR="$am_aux_dir/ar-lib $AR" + ;; +unknown) + m4_default([$1], + [AC_MSG_ERROR([could not determine $AR interface])]) + ;; +esac +AC_SUBST([AR])dnl +]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + AS_CASE([$CONFIG_FILES], + [*\'*], [eval set x "$CONFIG_FILES"], + [*], [set x $CONFIG_FILES]) + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`AS_DIRNAME(["$am_mf"])` + am_filepart=`AS_BASENAME(["$am_mf"])` + AM_RUN_LOG([cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles]) || am_rc=$? + done + if test $am_rc -ne 0; then + AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. Try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking).]) + fi + AS_UNSET([am_dirpart]) + AS_UNSET([am_filepart]) + AS_UNSET([am_mf]) + AS_UNSET([am_rc]) + rm -f conftest-deps.mk +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking is enabled. +# This creates each '.Po' and '.Plo' makefile fragment that we'll need in +# order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check whether make has an 'include' directive that can support all +# the idioms we need for our automatic dependency tracking code. +AC_DEFUN([AM_MAKE_INCLUDE], +[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) +cat > confinc.mk << 'END' +am__doit: + @echo this is the am__doit target >confinc.out +.PHONY: am__doit +END +am__include="#" +am__quote= +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) + AS_CASE([$?:`cat confinc.out 2>/dev/null`], + ['0:this is the am__doit target'], + [AS_CASE([$s], + [BSD], [am__include='.include' am__quote='"'], + [am__include='include' am__quote=''])]) + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +AC_MSG_RESULT([${_am_result}]) +AC_SUBST([am__include])]) +AC_SUBST([am__quote])]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([m4/ax_cxx_compile_stdcxx.m4]) +m4_include([m4/ax_pthread.m4]) +m4_include([m4/libtool.m4]) +m4_include([m4/ltoptions.m4]) +m4_include([m4/ltsugar.m4]) +m4_include([m4/ltversion.m4]) +m4_include([m4/lt~obsolete.m4]) diff --git a/ar-lib b/ar-lib new file mode 100644 index 0000000..0baa4f6 --- /dev/null +++ b/ar-lib @@ -0,0 +1,270 @@ +#! /bin/sh +# Wrapper for Microsoft lib.exe + +me=ar-lib +scriptversion=2012-03-01.08; # UTC + +# Copyright (C) 2010-2018 Free Software Foundation, Inc. +# Written by Peter Rosin . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + + +# func_error message +func_error () +{ + echo "$me: $1" 1>&2 + exit 1 +} + +file_conv= + +# func_file_conv build_file +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv in + mingw) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_at_file at_file operation archive +# Iterate over all members in AT_FILE performing OPERATION on ARCHIVE +# for each of them. +# When interpreting the content of the @FILE, do NOT use func_file_conv, +# since the user would need to supply preconverted file names to +# binutils ar, at least for MinGW. +func_at_file () +{ + operation=$2 + archive=$3 + at_file_contents=`cat "$1"` + eval set x "$at_file_contents" + shift + + for member + do + $AR -NOLOGO $operation:"$member" "$archive" || exit $? + done +} + +case $1 in + '') + func_error "no command. Try '$0 --help' for more information." + ;; + -h | --h*) + cat < +#include +#include + +#include + +#include "json/json_utilities.hpp" +#include "json/json_common.hpp" + +struct json_answer { + + // Utility function to accept both single and multiple value in the same interface + /** + * Generator of json_answer with result set to true + * @param cmd a copy of the command + * @param strategy a flag, an exception or a functor with no parameters returning either a string or a vector of strings + * @return an instance of json_answer + */ + template + static json_answer build_error(cmd::command cmd, const T& strategy) { + return build(cmd, strategy); + } + + /** + * Generator of json_answer with result set to false + * @param cmd a copy of the command + * @param strategy a flag, an exception or a functor with no parameters returning either a string or a vector of strings + * @return an instance of json_answer + */ + // Utility function to accept both single and multiple value in the same interface + template + static json_answer build_success(cmd::command cmd, const T& strategy) { + return build(cmd, strategy); + } + + /** + * Default constructor needed by nlohmann's JSON. + */ + json_answer() + : _cmd{cmd::command::UNKNOWN} + , _result{} + , _flag{answer::flag::UNKNOWN} + , _value{} { + } + + /** + * Convert JSON to json_answer + * @param args any input of nlohmann::json::parse representing a JSON + * @return an instance of json_answer parsing the input content + */ + template + static json_answer marshal(Args&& ...args) { + return nlohmann::json::parse(std::forward(args)...).template get(); + } + + /** + * Convert json_answer to JSON + * @return the JSON with no indentation + */ + nlohmann::json::string_t unmarshal() const { + return nlohmann::json(*this).dump(); + } + + cmd::command get_cmd() const noexcept { return _cmd; } + answer::flag get_flag() const noexcept { return _flag; } + bool get_result() const noexcept { return _result; } + const answer::value_t& get_value() const noexcept { return _value; } + + static constexpr auto& key_cmd() noexcept { return "cmd"; } + static constexpr auto& key_flag() noexcept { return "flag"; } + static constexpr auto& key_result() noexcept { return "result"; } + static constexpr auto& key_value() noexcept { return "value"; } + + friend void from_json(const nlohmann::json& j, json_answer& e) { + caen::json::get_if_not_null(j, key_cmd(), e._cmd); + caen::json::get_if_not_null(j, key_result(), e._result); + caen::json::get_if_not_null(j, key_flag(), e._flag); + caen::json::get_if_not_null(j, key_value(), e._value); + } + + friend void to_json(nlohmann::json& j, const json_answer& e) { + caen::json::set(j, key_cmd(), e._cmd); + caen::json::set(j, key_result(), e._result); + caen::json::set(j, key_flag(), e._flag); + caen::json::set(j, key_value(), e._value); + } + +private: + + template + static json_answer build_partial(cmd::command cmd) { + auto r = json_answer(); + r._cmd = cmd; + r._result = T; + return r; + } + + template + static json_answer build(cmd::command cmd, const std::exception& ex) { + auto r = build_partial(cmd); + r._value.emplace_back(ex.what()); + return r; + } + + template + static json_answer build(cmd::command cmd, const answer::flag_value_provider& strategy) { + auto r = build_partial(cmd); + if (strategy) + std::tie(r._flag, r._value) = strategy(); + return r; + } + + template + static json_answer build(cmd::command cmd, const answer::value_provider& strategy) { + auto r = build_partial(cmd); + if (strategy) // provider could be empty + r._value = strategy(); + return r; + } + + template + static json_answer build(cmd::command cmd, const answer::single_value_provider& strategy) { + auto r = build_partial(cmd); + if (strategy) // provider could be empty + r._value.push_back(strategy()); + return r; + } + + cmd::command _cmd; + bool _result; + answer::flag _flag; + answer::value_t _value; + +}; + +namespace answer { + +using namespace std::string_literals; + +NLOHMANN_JSON_SERIALIZE_ENUM(flag, { + { flag::UNKNOWN, nullptr }, + { flag::ARM, "ARM"s }, + { flag::DISARM, "DISARM"s }, + { flag::CLEAR, "CLEAR"s }, + { flag::RESET, "RESET"s }, +}) + +} // namespace answer + +#endif /* CAEN_INCLUDE_JSON_JSON_ANSWER_HPP_ */ diff --git a/backend-server/include/json/json_cmd.hpp b/backend-server/include/json/json_cmd.hpp new file mode 100644 index 0000000..d411e6c --- /dev/null +++ b/backend-server/include/json/json_cmd.hpp @@ -0,0 +1,162 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Back-end Server. +* +* The CAEN Back-end Server is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* TheCAEN Back-end Server is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Back-end Server; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file json_cmd.hpp +* \brief +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_JSON_JSON_CMD_HPP_ +#define CAEN_INCLUDE_JSON_JSON_CMD_HPP_ + +#include + +#include + +#include "json/json_common.hpp" +#include "json/json_utilities.hpp" + +struct json_cmd { + + /** + * Generator of json_cmd + * @param cmd + * @param handle + * @param query + * @param value + * @return an instance of json_cmd + */ + template + static json_cmd build(cmd::command cmd, cmd::handle_t handle, QueryT&& query = QueryT{}, ValueT&& value = ValueT{}) { + json_cmd r; + r._cmd = cmd; + r._handle = handle; + r._query = std::forward(query); + r._value = std::forward(value); + return r; + } + + /** + * Default constructor needed by nlohmann's JSON. + */ + json_cmd() + : _cmd{cmd::command::UNKNOWN} + , _handle{} + , _query{} + , _multiple_query{} + , _value{} + , _multiple_value{} { + } + + /** + * Convert JSON to json_cmd + * @param args any input of nlohmann::json::parse representing a JSON + * @return an instance of json_cmd parsing the input content + */ + template + static json_cmd marshal(Args&& ...args) { + return nlohmann::json::parse(std::forward(args)...).template get(); + } + + /** + * Convert json_cmd to JSON + * @return the JSON with no indentation + */ + nlohmann::json::string_t unmarshal() const { + return nlohmann::json(*this).dump(); + } + + cmd::command get_cmd() const noexcept { return _cmd; } + cmd::handle_t get_handle() const noexcept { return _handle; } + const cmd::query_t& get_query() const noexcept { return _query; } + const cmd::multiple_query_t& get_multiple_query() const noexcept { return _multiple_query; } + const cmd::value_t& get_value() const noexcept { return _value; } + const cmd::multiple_value_t& get_multiple_value() const noexcept { return _multiple_value; } + + static constexpr auto& key_cmd() noexcept { return "cmd"; } + static constexpr auto& key_handle() noexcept { return "handle"; } + static constexpr auto& key_query() noexcept { return "query"; } + static constexpr auto& key_multiple_query() noexcept { return "multipleQuery"; } + static constexpr auto& key_value() noexcept { return "value"; } + static constexpr auto& key_multiple_value() noexcept { return "multipleValue"; } + + friend void from_json(const nlohmann::json& j, json_cmd& e) { + caen::json::get_if_not_null(j, key_cmd(), e._cmd); + caen::json::get_if_not_null(j, key_handle(), e._handle); + caen::json::get_if_not_null(j, key_query(), e._query); + caen::json::get_if_not_null(j, key_multiple_query(), e._multiple_query); + caen::json::get_if_not_null(j, key_value(), e._value); + caen::json::get_if_not_null(j, key_multiple_value(), e._multiple_value); + } + + friend void to_json(nlohmann::json& j, const json_cmd& e) { + caen::json::set(j, key_cmd(), e._cmd); + caen::json::set(j, key_handle(), e._handle); + caen::json::set(j, key_query(), e._query); + caen::json::set(j, key_multiple_query(), e._multiple_query); + caen::json::set(j, key_value(), e._value); + caen::json::set(j, key_multiple_value(), e._multiple_value); + } + +private: + + cmd::command _cmd; + cmd::handle_t _handle; + cmd::query_t _query; + cmd::multiple_query_t _multiple_query; + cmd::value_t _value; + cmd::multiple_value_t _multiple_value; + +}; + +namespace cmd { + +using namespace std::string_literals; + +NLOHMANN_JSON_SERIALIZE_ENUM(command, { + { command::UNKNOWN, nullptr }, + { command::CONNECT, "connect"s }, + { command::GET_DEVICE_TREE, "getDeviceTree"s }, + { command::GET_CHILD_HANDLES, "getChildHandles"s }, + { command::GET_HANDLE, "getHandle"s }, + { command::GET_PARENT_HANDLE, "getParentHandle"s }, + { command::GET_PATH, "getPath"s }, + { command::GET_NODE_PROPERTIES, "getNodeProperties"s }, + { command::GET_VALUE, "getValue"s }, + { command::MULTI_GET_VALUE, "multiGetValue"s }, + { command::SET_VALUE, "setValue"s }, + { command::MULTI_SET_VALUE, "multiSetValue"s }, + { command::SEND_COMMAND, "sendCommand"s }, +}) + +} // namespace cmd + +#endif /* CAEN_INCLUDE_JSON_JSON_CMD_HPP_ */ diff --git a/backend-server/include/json/json_common.hpp b/backend-server/include/json/json_common.hpp new file mode 100644 index 0000000..498e62f --- /dev/null +++ b/backend-server/include/json/json_common.hpp @@ -0,0 +1,108 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Back-end Server. +* +* The CAEN Back-end Server is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* TheCAEN Back-end Server is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Back-end Server; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file json_common.hpp +* \brief +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_JSON_JSON_COMMON_HPP_ +#define CAEN_INCLUDE_JSON_JSON_COMMON_HPP_ + +struct json_cmd; // forward declaration +struct json_answer; // forward declaration + +#include +#include +#include +#include +#include +#include + +#include + +namespace cmd { + +enum class command { + UNKNOWN, + CONNECT, + GET_DEVICE_TREE, + GET_HANDLE, + GET_CHILD_HANDLES, + GET_PARENT_HANDLE, + GET_PATH, + GET_NODE_PROPERTIES, + GET_VALUE, + MULTI_GET_VALUE, + SET_VALUE, + MULTI_SET_VALUE, + SEND_COMMAND, +}; + +using handle_t = std::uint32_t; +using query_t = std::string; +using multiple_query_t = std::vector; +using value_t = std::string; +using multiple_value_t = std::vector; + +static constexpr std::size_t handle_bits{24}; +static constexpr handle_t max_handle{(handle_t{1} << handle_bits) - 1}; // reserved use + +static_assert(handle_bits < sizeof(handle_t) * CHAR_BIT, "handle_t is too small to store handle_bits"); + +} // namespace cmd + +namespace answer { + +enum class flag { + UNKNOWN, + ARM, + DISARM, + CLEAR, + RESET, +}; + +using single_value_t = std::string; +using single_value_provider = std::function; +using value_t = std::vector; +using value_provider = std::function; +using flag_value_t = std::pair; +using flag_value_provider = std::function; + +} // namespace answer + +namespace nt { + +using node_type = ::CAEN_FELib_NodeType_t; + +} // namespace nt + +#endif /* CAEN_INCLUDE_JSON_JSON_COMMON_HPP_ */ diff --git a/backend-server/include/json/json_element.hpp b/backend-server/include/json/json_element.hpp new file mode 100644 index 0000000..08362fe --- /dev/null +++ b/backend-server/include/json/json_element.hpp @@ -0,0 +1,238 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Back-end Server. +* +* The CAEN Back-end Server is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* TheCAEN Back-end Server is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Back-end Server; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file json_element.hpp +* \brief +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_JSON_JSON_ELEMENT_HPP_ +#define CAEN_INCLUDE_JSON_JSON_ELEMENT_HPP_ + +#include +#include + +#include + +#include "cpp-utility/optional.hpp" +#include "json/json_utilities.hpp" +#include "json/json_element_fwd.hpp" + +struct json_element { + + json_element() + : _name{} + , _is_visible{} + , _description{} + , _node_type{} + , _access_mode{} + , _level{} + , _data_type{} + , _index_string{} + , _index{} + , _default_value{} + , _min_value{} + , _max_value{} + , _increment{} + , _multiple_value{} + , _allowed_values{} + , _uom{} + , _exp_uom{} + , _set_in_run{} { + }; + + /** + * Convert JSON to json_element + * @param args any input of nlohmann::json::parse representing a JSON + * @return an instance of json_cmd parsing the input content + */ + template + static json_element marshal(Args&& ...args) { + return nlohmann::json::parse(std::forward(args)...).template get(); + } + + /** + * Convert json_element to JSON + * @return the JSON with no indentation + */ + nlohmann::json::string_t unmarshal() const { + return nlohmann::json(*this).dump(); + } + + static constexpr auto& key_name() noexcept { return "name"; } + static constexpr auto& key_description() noexcept { return "description"; } + static constexpr auto& key_node_type() noexcept { return "nodeType"; } + static constexpr auto& key_access_mode() noexcept { return "accessMode"; } + static constexpr auto& key_level() noexcept { return "level"; } + static constexpr auto& key_data_type() noexcept { return "dataType"; } + static constexpr auto& key_index_string() noexcept { return "indexString"; } + static constexpr auto& key_index() noexcept { return "index"; } + static constexpr auto& key_default_value() noexcept { return "defaultValue"; } + static constexpr auto& key_min_value() noexcept { return "minValue"; } + static constexpr auto& key_max_value() noexcept { return "maxValue"; } + static constexpr auto& key_increment() noexcept { return "increment"; } + static constexpr auto& key_multiple_value() noexcept { return "multipleValue"; } + static constexpr auto& key_allowed_values() noexcept { return "allowedValues"; } + static constexpr auto& key_uom() noexcept { return "UOM"; } + static constexpr auto& key_exp_uom() noexcept { return "ExpUOM"; } + static constexpr auto& key_set_in_run() noexcept { return "setInRun"; } + static constexpr auto& key_is_visible() noexcept { return "isVisible"; } + static constexpr auto& key_arg_in_get() noexcept { return "argInGet"; } + + friend void from_json(const nlohmann::json& j, json_element& e) { + caen::json::get(j, key_name(), e._name); + caen::json::get(j, key_is_visible(), e._is_visible); + caen::json::get_if_not_null(j, key_description(), e._description); + caen::json::get_if_not_null(j, key_node_type(), e._node_type); + caen::json::get_if_not_null(j, key_access_mode(), e._access_mode); + caen::json::get_if_not_null(j, key_level(), e._level); + caen::json::get_if_not_null(j, key_data_type(), e._data_type); + caen::json::get_if_not_null(j, key_index_string(), e._index_string); + caen::json::get_if_not_null(j, key_index(), e._index); + caen::json::get_if_not_null(j, key_default_value(), e._default_value); + caen::json::get_if_not_null(j, key_min_value(), e._min_value); + caen::json::get_if_not_null(j, key_max_value(), e._max_value); + caen::json::get_if_not_null(j, key_increment(), e._increment); + caen::json::get_if_not_null(j, key_allowed_values(), e._allowed_values); + caen::json::get_if_not_null(j, key_multiple_value(), e._multiple_value); + caen::json::get_if_not_null(j, key_uom(), e._uom); + caen::json::get_if_not_null(j, key_exp_uom(), e._exp_uom); + caen::json::get_if_not_null(j, key_set_in_run(), e._set_in_run); + caen::json::get_if_not_null(j, key_arg_in_get(), e._arg_in_get); + } + + friend void to_json(nlohmann::json& j, const json_element& e) { + caen::json::set(j, key_name(), e._name); + caen::json::set(j, key_is_visible(), e._is_visible); + caen::json::set(j, key_description(), e._description); + caen::json::set(j, key_node_type(), e._node_type); + caen::json::set(j, key_access_mode(), e._access_mode); + caen::json::set(j, key_level(), e._level); + caen::json::set(j, key_data_type(), e._data_type); + caen::json::set(j, key_index_string(), e._index_string); + caen::json::set(j, key_index(), e._index); + caen::json::set(j, key_default_value(), e._default_value); + caen::json::set(j, key_min_value(), e._min_value); + caen::json::set(j, key_max_value(), e._max_value); + caen::json::set(j, key_increment(), e._increment); + caen::json::set(j, key_multiple_value(), e._multiple_value); + caen::json::set(j, key_allowed_values(), e._allowed_values); + caen::json::set(j, key_uom(), e._uom); + caen::json::set(j, key_exp_uom(), e._exp_uom); + caen::json::set(j, key_set_in_run(), e._set_in_run); + caen::json::set(j, key_arg_in_get(), e._arg_in_get); + } + + // Getters + auto& get_name() const noexcept { return _name; } + auto get_is_visible() const noexcept { return _is_visible; } + auto& get_description() const noexcept { return _description; } + auto& get_node_type() const noexcept { return _node_type; } + auto& get_access_mode() const noexcept { return _access_mode; } + auto& get_level() const noexcept { return _level; } + auto& get_data_type() const noexcept { return _data_type; } + auto& get_index() const noexcept { return _index; } + auto& get_index_string() const noexcept { return _index_string; } + auto& get_default_value() const noexcept { return _default_value; } + auto& get_min_value() const noexcept { return _min_value; } + auto& get_max_value() const noexcept { return _max_value; } + auto& get_increment() const noexcept { return _increment; } + auto& get_multiple_value() const noexcept { return _multiple_value; } + auto& get_allowed_values() const noexcept { return _allowed_values; } + auto& get_uom() const noexcept { return _uom; } + auto& get_exp_uom() const noexcept { return _exp_uom; } + auto& get_set_in_run() const noexcept { return _set_in_run; } + auto& get_arg_in_get() const noexcept { return _arg_in_get; } + +private: + + std::string _name; + bool _is_visible; + + caen::optional _description; + caen::optional _node_type; + caen::optional _access_mode; + caen::optional _level; + caen::optional _data_type; + caen::optional> _index_string; + caen::optional> _index; + caen::optional _default_value; + caen::optional _min_value; + caen::optional _max_value; + caen::optional _increment; + caen::optional _multiple_value; + caen::optional> _allowed_values; + caen::optional _uom; + caen::optional _exp_uom; + caen::optional _set_in_run; + caen::optional _arg_in_get; + +}; + +namespace element { + +using namespace std::string_literals; + +NLOHMANN_JSON_SERIALIZE_ENUM(node_type, { + { node_type::UNKNOWN, nullptr }, + { node_type::PARAMETER, "PARAMETER"s }, + { node_type::CMD, "CMD"s }, + { node_type::ENDPOINT, "ENDPOINT"s }, + { node_type::FEATURE, "FEATURE"s }, +}) + +NLOHMANN_JSON_SERIALIZE_ENUM(data_type, { + { data_type::UNKNOWN, nullptr }, + { data_type::STRING, "STRING"s }, + { data_type::NUMBER, "NUMBER"s }, +}) + +NLOHMANN_JSON_SERIALIZE_ENUM(access_mode, { + { access_mode::UNKNOWN, nullptr }, + { access_mode::READ_ONLY, "READ_ONLY"s }, + { access_mode::WRITE_ONLY, "WRITE_ONLY"s }, + { access_mode::READ_WRITE, "READ_WRITE"s }, +}) + +NLOHMANN_JSON_SERIALIZE_ENUM(level, { + { level::UNKNOWN, nullptr }, + { level::DIGITIZER, "DIG"s }, + { level::CHANNEL, "CH"s }, + { level::LVDS, "LVDS"s }, + { level::VGA, "VGA"s }, + { level::ENDPOINT, "ENDPOINT"s }, + { level::FOLDER, "FOLDER"s }, + { level::GROUP, "GROUP"s }, +}) + +} // namespace element + +#endif /* CAEN_INCLUDE_JSON_JSON_ELEMENT_HPP_ */ diff --git a/backend-server/include/json/json_element_fwd.hpp b/backend-server/include/json/json_element_fwd.hpp new file mode 100644 index 0000000..3575a5c --- /dev/null +++ b/backend-server/include/json/json_element_fwd.hpp @@ -0,0 +1,78 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Back-end Server. +* +* The CAEN Back-end Server is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* TheCAEN Back-end Server is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Back-end Server; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file json_element_fwd.hpp +* \brief +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_JSON_JSON_ELEMENT_FWD_HPP_ +#define CAEN_INCLUDE_JSON_JSON_ELEMENT_FWD_HPP_ + +struct json_element; + +namespace element { + +enum class node_type { + UNKNOWN, + PARAMETER, + FEATURE, + ENDPOINT, + CMD, +}; + +enum class data_type { + UNKNOWN, + STRING, + NUMBER, +}; + +enum class access_mode { + UNKNOWN, + READ_ONLY, + WRITE_ONLY, + READ_WRITE, +}; + +enum class level { + UNKNOWN, + DIGITIZER, + CHANNEL, + LVDS, + VGA, + ENDPOINT, + FOLDER, + GROUP, +}; + +} // namespace element + +#endif /* CAEN_INCLUDE_JSON_JSON_ELEMENT_FWD_HPP_ */ diff --git a/backend-server/include/json/json_node_type.hpp b/backend-server/include/json/json_node_type.hpp new file mode 100644 index 0000000..cb82a85 --- /dev/null +++ b/backend-server/include/json/json_node_type.hpp @@ -0,0 +1,63 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Back-end Server. +* +* The CAEN Back-end Server is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* TheCAEN Back-end Server is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Back-end Server; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file json_node_type.hpp +* \brief +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_JSON_JSON_NODE_TYPE_HPP_ +#define CAEN_INCLUDE_JSON_JSON_NODE_TYPE_HPP_ + +#include + +#include "json/json_common.hpp" + +// To be defined in global namespace, as CAEN_FELib_NodeType_t is in a C header +NLOHMANN_JSON_SERIALIZE_ENUM(nt::node_type, { + { nt::node_type::CAEN_FELib_UNKNOWN, nullptr }, + { nt::node_type::CAEN_FELib_PARAMETER, "PARAMETER" }, + { nt::node_type::CAEN_FELib_COMMAND, "COMMAND" }, + { nt::node_type::CAEN_FELib_FEATURE, "FEATURE" }, + { nt::node_type::CAEN_FELib_ATTRIBUTE, "ATTRIBUTE" }, + { nt::node_type::CAEN_FELib_ENDPOINT, "ENDPOINT" }, + { nt::node_type::CAEN_FELib_CHANNEL, "CHANNEL" }, + { nt::node_type::CAEN_FELib_DIGITIZER, "DIGITIZER" }, + { nt::node_type::CAEN_FELib_FOLDER, "FOLDER" }, + { nt::node_type::CAEN_FELib_LVDS, "LVDS" }, + { nt::node_type::CAEN_FELib_VGA, "VGA" }, + { nt::node_type::CAEN_FELib_HV_CHANNEL, "HV_CHANNEL" }, + { nt::node_type::CAEN_FELib_MONOUT, "MONOUT" }, + { nt::node_type::CAEN_FELib_VTRACE, "VTRACE" }, + { nt::node_type::CAEN_FELib_GROUP, "GROUP" }, +}) + +#endif /* CAEN_INCLUDE_JSON_JSON_NODE_TYPE_HPP_ */ diff --git a/backend-server/include/json/json_utilities.hpp b/backend-server/include/json/json_utilities.hpp new file mode 100644 index 0000000..3838682 --- /dev/null +++ b/backend-server/include/json/json_utilities.hpp @@ -0,0 +1,159 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Back-end Server. +* +* The CAEN Back-end Server is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* TheCAEN Back-end Server is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Back-end Server; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file json_utilities.hpp +* \brief +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_JSON_JSON_UTILITIES_HPP_ +#define CAEN_INCLUDE_JSON_JSON_UTILITIES_HPP_ + +#include + +#include + +#include "cpp-utility/optional.hpp" + +// partial specialization for caen::optional +namespace nlohmann { + +template +struct adl_serializer> { + static void to_json(json& j, const caen::optional& opt) { + if (!opt) + j = nullptr; + else + j = *opt; + } + static void from_json(const json& j, caen::optional& opt) { + if (j.is_null()) + opt = caen::nullopt; + else + opt = j.get(); + } +}; + +} // namespace nlohmann + +namespace caen { + +namespace json { + +template +void get(const BasicJsonType& j, TKey&& key, T& value) { + j.at(std::forward(key)).get_to(value); // may throw +} + +template +void get_if_not_null(const BasicJsonType& j, TKey&& key, T& value) { + const auto it = j.find(std::forward(key)); + if (it != j.end() && !it->is_null()) + it->get_to(value); +} + +template +void set(BasicJsonType& j, TKey&& key, T&& value) { + j[std::forward(key)] = std::forward(value); +} + +/** + * Convert a type (enum, in particular), to string version, using to_json + * @tparam T input type + * @param v value + * @return a string that can be converted back to enum from_json + */ +template +String to_json_string(T&& v) { + return nlohmann::json(std::forward(v)).get(); +} + +/** + * Non-throwing version of to_json_string(), useful for error logging + * @tparam T input type + * @param v value + * @return same of to_json_string(), empty string if conversion cannot be performed. + */ +template +String to_json_string_safe(T&& v) noexcept try { + return to_json_string(std::forward(v)); +} +catch (...) { + return String{}; +} + +/** + * Utility function to recursively iterate across all element of a nlohmann::json + * @sa https://stackoverflow.com/q/45934851/3287591 +*/ +template +void json_recursive_for_each(BasicJsonType& j, UnaryFunction f) noexcept(noexcept(f)) { + for (auto it = std::begin(j); it != std::end(j); ++it) { + if (it->is_structured()) + json_recursive_for_each(*it, f); + f(it); + } +} + +/** + * Utility function to recursively iterate across all element of a nlohmann::json + * @sa https://stackoverflow.com/q/45934851/3287591 +*/ +template +void json_recursive_erase_if(BasicJsonType& j, UnaryFunction f) { + for (auto it = std::begin(j); it != std::end(j);) { + if (it->is_structured()) + json_recursive_erase_if(*it, f); + if (f(it)) + it = j.erase(it); + else + ++it; + } +} + +} // namespace json + +inline namespace literals { + +/** + * Version of _json_pointer that force the input to lower case +*/ +inline nlohmann::json::json_pointer operator""_json_pointer_lowercase(const char* s, std::size_t n) { + std::string path(s, n); + boost::to_lower(path); + return nlohmann::json::json_pointer(path); +} + +} // namespace literals + +} // namespace caen + +#endif /* CAEN_INCLUDE_JSON_JSON_UTILITIES_HPP_ */ diff --git a/backend-server/include/server_definitions.hpp b/backend-server/include/server_definitions.hpp new file mode 100644 index 0000000..e4c7fd9 --- /dev/null +++ b/backend-server/include/server_definitions.hpp @@ -0,0 +1,65 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Back-end Server. +* +* The CAEN Back-end Server is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* TheCAEN Back-end Server is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Back-end Server; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file server_definitions.hpp +* \brief +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_SERVER_DEFINITIONS_HPP_ +#define CAEN_INCLUDE_SERVER_DEFINITIONS_HPP_ + +#define BACKEND_SERVER_STR_HELPER(S) #S +#define BACKEND_SERVER_STR(S) BACKEND_SERVER_STR_HELPER(S) + +#define BACKEND_SERVER_VERSION_MAJOR 1 +#define BACKEND_SERVER_VERSION_MINOR 4 +#define BACKEND_SERVER_VERSION_PATCH 2 +#define BACKEND_SERVER_VERSION (BACKEND_SERVER_VERSION_MAJOR * 10000) + (BACKEND_SERVER_VERSION_MINOR * 100) + (BACKEND_SERVER_VERSION_PATCH) +#define BACKEND_SERVER_VERSION_STRING BACKEND_SERVER_STR(BACKEND_SERVER_VERSION_MAJOR) "." BACKEND_SERVER_STR(BACKEND_SERVER_VERSION_MINOR) "." BACKEND_SERVER_STR(BACKEND_SERVER_VERSION_PATCH) + +#ifdef __cplusplus // to expose previous code also in C + +#include + +namespace server_definitions { + +constexpr unsigned int version{BACKEND_SERVER_VERSION}; +constexpr std::size_t header_size{1 << 5}; +constexpr unsigned short command_port{0xcae0}; +constexpr unsigned short rest_port{0xcae2}; +constexpr unsigned short udp_port{0xcae4}; + +} // namespace server_definitions + +#endif + +#endif /* CAEN_INCLUDE_SERVER_DEFINITIONS_HPP_ */ diff --git a/compile b/compile new file mode 100644 index 0000000..99e5052 --- /dev/null +++ b/compile @@ -0,0 +1,348 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ + icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/config.guess b/config.guess new file mode 100644 index 0000000..f50dcdb --- /dev/null +++ b/config.guess @@ -0,0 +1,1480 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2018 Free Software Foundation, Inc. + +timestamp='2018-02-24' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2018 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > "$dummy.c" ; + for c in cc gcc c89 c99 ; do + if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "$UNAME_SYSTEM" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval "$set_cc_for_build" + cat <<-EOF > "$dummy.c" + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" + + # If ldd exists, use it to detect musl libc. + if command -v ldd >/dev/null && \ + ldd --version 2>&1 | grep -q ^musl + then + LIBC=musl + fi + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + "/sbin/$sysctl" 2>/dev/null || \ + "/usr/sbin/$sysctl" 2>/dev/null || \ + echo unknown)` + case "$UNAME_MACHINE_ARCH" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine="${arch}${endian}"-unknown + ;; + *) machine="$UNAME_MACHINE_ARCH"-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "$UNAME_MACHINE_ARCH" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval "$set_cc_for_build" + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "$UNAME_MACHINE_ARCH" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "$UNAME_VERSION" in + Debian*) + release='-gnu' + ;; + *) + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "$machine-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" + exit ;; + *:MidnightBSD:*:*) + echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" + exit ;; + *:ekkoBSD:*:*) + echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" + exit ;; + *:SolidBSD:*:*) + echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd"$UNAME_RELEASE" + exit ;; + *:MirBSD:*:*) + echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" + exit ;; + *:Sortix:*:*) + echo "$UNAME_MACHINE"-unknown-sortix + exit ;; + *:Redox:*:*) + echo "$UNAME_MACHINE"-unknown-redox + exit ;; + mips:OSF1:*.*) + echo mips-dec-osf1 + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo "$UNAME_MACHINE"-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo "$UNAME_MACHINE"-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix"$UNAME_RELEASE" + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux"$UNAME_RELEASE" + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval "$set_cc_for_build" + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos"$UNAME_RELEASE" + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos"$UNAME_RELEASE" + ;; + sun4) + echo sparc-sun-sunos"$UNAME_RELEASE" + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos"$UNAME_RELEASE" + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint"$UNAME_RELEASE" + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint"$UNAME_RELEASE" + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint"$UNAME_RELEASE" + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten"$UNAME_RELEASE" + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten"$UNAME_RELEASE" + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix"$UNAME_RELEASE" + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix"$UNAME_RELEASE" + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix"$UNAME_RELEASE" + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos"$UNAME_RELEASE" + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] + then + if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ + [ "$TARGET_BINARY_INTERFACE"x = x ] + then + echo m88k-dg-dgux"$UNAME_RELEASE" + else + echo m88k-dg-dguxbcs"$UNAME_RELEASE" + fi + else + echo i586-dg-dgux"$UNAME_RELEASE" + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + fi + echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + fi + echo "$IBM_ARCH"-ibm-aix"$IBM_REV" + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + case "$UNAME_MACHINE" in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "$sc_cpu_version" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "$sc_kernel_bits" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "$HP_ARCH" = "" ]; then + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ "$HP_ARCH" = hppa2.0w ] + then + eval "$set_cc_for_build" + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo "$HP_ARCH"-hp-hpux"$HPUX_REV" + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux"$HPUX_REV" + exit ;; + 3050*:HI-UX:*:*) + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo "$UNAME_MACHINE"-unknown-osf1mk + else + echo "$UNAME_MACHINE"-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi"$UNAME_RELEASE" + exit ;; + *:BSD/OS:*:*) + echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case "$UNAME_PROCESSOR" in + amd64) + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; + esac + echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" + exit ;; + i*:CYGWIN*:*) + echo "$UNAME_MACHINE"-pc-cygwin + exit ;; + *:MINGW64*:*) + echo "$UNAME_MACHINE"-pc-mingw64 + exit ;; + *:MINGW*:*) + echo "$UNAME_MACHINE"-pc-mingw32 + exit ;; + *:MSYS*:*) + echo "$UNAME_MACHINE"-pc-msys + exit ;; + i*:PW*:*) + echo "$UNAME_MACHINE"-pc-pw32 + exit ;; + *:Interix*:*) + case "$UNAME_MACHINE" in + x86) + echo i586-pc-interix"$UNAME_RELEASE" + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix"$UNAME_RELEASE" + exit ;; + IA64) + echo ia64-unknown-interix"$UNAME_RELEASE" + exit ;; + esac ;; + i*:UWIN*:*) + echo "$UNAME_MACHINE"-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + *:GNU:*:*) + # the GNU system + echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" + exit ;; + i*86:Minix:*:*) + echo "$UNAME_MACHINE"-pc-minix + exit ;; + aarch64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + arm*:Linux:*:*) + eval "$set_cc_for_build" + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi + else + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + cris:Linux:*:*) + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" + exit ;; + crisv32:Linux:*:*) + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" + exit ;; + e2k:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + frv:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + hexagon:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + i*86:Linux:*:*) + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" + exit ;; + ia64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + k1om:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + m32r*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + m68*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`" + test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; } + ;; + mips64el:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-"$LIBC" + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-"$LIBC" + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-"$LIBC" + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; + PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; + *) echo hppa-unknown-linux-"$LIBC" ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-"$LIBC" + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-"$LIBC" + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-"$LIBC" + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-"$LIBC" + exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" + exit ;; + sh64*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + sh*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + tile*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + vax:Linux:*:*) + echo "$UNAME_MACHINE"-dec-linux-"$LIBC" + exit ;; + x86_64:Linux:*:*) + if objdump -f /bin/sh | grep -q elf32-x86-64; then + echo "$UNAME_MACHINE"-pc-linux-"$LIBC"x32 + else + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" + fi + exit ;; + xtensa*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo "$UNAME_MACHINE"-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo "$UNAME_MACHINE"-unknown-stop + exit ;; + i*86:atheos:*:*) + echo "$UNAME_MACHINE"-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo "$UNAME_MACHINE"-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos"$UNAME_RELEASE" + exit ;; + i*86:*DOS:*:*) + echo "$UNAME_MACHINE"-pc-msdosdjgpp + exit ;; + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" + else + echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}" + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" + else + echo "$UNAME_MACHINE"-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos"$UNAME_RELEASE" + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos"$UNAME_RELEASE" + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos"$UNAME_RELEASE" + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos"$UNAME_RELEASE" + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv"$UNAME_RELEASE" + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo "$UNAME_MACHINE"-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo "$UNAME_MACHINE"-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux"$UNAME_RELEASE" + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv"$UNAME_RELEASE" + else + echo mips-unknown-sysv"$UNAME_RELEASE" + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux"$UNAME_RELEASE" + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux"$UNAME_RELEASE" + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux"$UNAME_RELEASE" + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux"$UNAME_RELEASE" + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux"$UNAME_RELEASE" + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux"$UNAME_RELEASE" + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux"$UNAME_RELEASE" + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody"$UNAME_RELEASE" + exit ;; + *:Rhapsody:*:*) + echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval "$set_cc_for_build" + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-*:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSR-*:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSV-*:NONSTOP_KERNEL:*:*) + echo nsv-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSX-*:NONSTOP_KERNEL:*:*) + echo nsx-tandem-nsk"$UNAME_RELEASE" + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo "$UNAME_MACHINE"-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux"$UNAME_RELEASE" + exit ;; + *:DragonFly:*:*) + echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "$UNAME_MACHINE" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" + exit ;; + i*86:rdos:*:*) + echo "$UNAME_MACHINE"-pc-rdos + exit ;; + i*86:AROS:*:*) + echo "$UNAME_MACHINE"-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo "$UNAME_MACHINE"-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +echo "$0: unable to guess system type" >&2 + +case "$UNAME_MACHINE:$UNAME_SYSTEM" in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-functions 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.sub b/config.sub new file mode 100644 index 0000000..1d8e98b --- /dev/null +++ b/config.sub @@ -0,0 +1,1801 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2018 Free Software Foundation, Inc. + +timestamp='2018-02-22' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2018 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo "$1" + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo "$1" | sed 's/-[^-]*$//'` + if [ "$basic_machine" != "$1" ] + then os=`echo "$1" | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia16 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | wasm32 \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | wasm32-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-pc + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2*) + basic_machine=m68k-bull + os=-sysv3 + ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=$os"spe" + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=-linux + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + nsv-tandem) + basic_machine=nsv-tandem + ;; + nsx-tandem) + basic_machine=nsx-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + x64) + basic_machine=x86_64-pc + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases that might get confused + # with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # es1800 is here to avoid being matched by es* (a different OS) + -es1800*) + os=-ose + ;; + # Now accept the basic system types. + # The portable systems comes first. + # Each alternative MUST end in a * to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \ + | -midnightbsd*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -xray | -os68k* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo "$os" | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo "$os" | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo "$os" | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4*) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -pikeos*) + # Until real need of OS specific support for + # particular features comes up, bare metal + # configurations are quite functional. + case $basic_machine in + arm*) + os=-eabi + ;; + *) + os=-elf + ;; + esac + ;; + -nacl*) + ;; + -ios) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + pru-*) + os=-elf + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"` + ;; +esac + +echo "$basic_machine$os" +exit + +# Local variables: +# eval: (add-hook 'write-file-functions 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100644 index 0000000..4ce7722 --- /dev/null +++ b/configure @@ -0,0 +1,23334 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for CAEN_Dig2 v1.6.1. +# +# Report bugs to . +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: support.computing@caen.it about your system, including +$0: any error possibly output before this message. Then +$0: install a modern shell, or manually run the script +$0: under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='CAEN_Dig2' +PACKAGE_TARNAME='caen_dig2' +PACKAGE_VERSION='v1.6.1' +PACKAGE_STRING='CAEN_Dig2 v1.6.1' +PACKAGE_BUGREPORT='support.computing@caen.it' +PACKAGE_URL='' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +BOOST_LDFLAGS +BOOST_CPPFLAGS +PTHREAD_CFLAGS +PTHREAD_LIBS +PTHREAD_CXX +PTHREAD_CC +ax_pthread_config +HAVE_CXX20 +HAVE_CXX17 +HAVE_CXX14 +CXXCPP +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +CPP +LT_SYS_LIBRARY_PATH +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +DLLTOOL +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +LIBTOOL +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +ac_ct_AR +AR +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL +am__quote' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_dependency_tracking +enable_static +enable_shared +with_pic +enable_fast_install +with_aix_soname +with_gnu_ld +with_sysroot +enable_libtool_lock +enable_assert +with_boost +with_boost_libdir +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +LT_SYS_LIBRARY_PATH +CPP +CXX +CXXFLAGS +CCC +CXXCPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures CAEN_Dig2 v1.6.1 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/caen_dig2] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of CAEN_Dig2 v1.6.1:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-silent-rules less verbose build output (undo: "make V=1") + --disable-silent-rules verbose build output (undo: "make V=0") + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --enable-static[=PKGS] build static libraries [default=no] + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --disable-assert turn off assertions + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-aix-soname=aix|svr4|both + shared library versioning (aka "SONAME") variant to + provide on AIX, [default=aix]. + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot[=DIR] Search for dependent libraries within DIR (or the + compiler's sysroot if not specified). + --with-boost[=ARG] use Boost library from a standard location + (ARG=yes), from the specified location (ARG=), + or disable it (ARG=no) [ARG=yes] + --with-boost-libdir=LIB_DIR + Force given directory for boost libraries. Note that + this will override library path detection, so use + this parameter only if default library detection + fails and you know exactly where your boost + libraries are located. + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + LT_SYS_LIBRARY_PATH + User-defined run-time library search path. + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CXXCPP C++ preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +CAEN_Dig2 configure v1.6.1 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link + +# ac_fn_cxx_try_run LINENO +# ------------------------ +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_cxx_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_run + +# ac_fn_cxx_compute_int LINENO EXPR VAR INCLUDES +# ---------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_cxx_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + echo >>conftest.val; read $3 &5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( $as_echo "## ---------------------------------------- ## +## Report this to support.computing@caen.it ## +## ---------------------------------------- ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_header_mongrel +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by CAEN_Dig2 $as_me v1.6.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# Search in m4 folder for custom macros. It requires also ACLOCAL_AMFLAGS on +# Makefile.am, unless we use AC_CONFIG_MACRO_DIRS introduced on autoconf 2.70. + + +# tar-ustar required to remove the filename length limit on default tar-v7 format +# is old enough to be supported everywhere +am__api_version='1.16' + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken + alias in your environment" "$LINENO" 5 + fi + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='caen_dig2' + VERSION='v1.6.1' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar plaintar pax cpio none' + +# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 +$as_echo_n "checking whether UID '$am_uid' is supported by ustar format... " >&6; } + if test $am_uid -le $am_max_uid; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + _am_tools=none + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 +$as_echo_n "checking whether GID '$am_gid' is supported by ustar format... " >&6; } + if test $am_gid -le $am_max_gid; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + _am_tools=none + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 +$as_echo_n "checking how to create a ustar tar archive... " >&6; } + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_ustar-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + { echo "$as_me:$LINENO: $_am_tar --version" >&5 + ($_am_tar --version) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && break + done + am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x ustar -w "$$tardir"' + am__tar_='pax -L -x ustar -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H ustar -L' + am__tar_='find "$tardir" -print | cpio -o -H ustar -L' + am__untar='cpio -i -H ustar -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_ustar}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 + (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + rm -rf conftest.dir + if test -s conftest.tar; then + { echo "$as_me:$LINENO: $am__untar &5 + ($am__untar &5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + { echo "$as_me:$LINENO: cat conftest.dir/file" >&5 + (cat conftest.dir/file) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + if ${am_cv_prog_tar_ustar+:} false; then : + $as_echo_n "(cached) " >&6 +else + am_cv_prog_tar_ustar=$_am_tool +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 +$as_echo "$am_cv_prog_tar_ustar" >&6; } + + + + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 +$as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; } +cat > confinc.mk << 'END' +am__doit: + @echo this is the am__doit target >confinc.out +.PHONY: am__doit +END +am__include="#" +am__quote= +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 + (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + case $?:`cat confinc.out 2>/dev/null` in #( + '0:this is the am__doit target') : + case $s in #( + BSD) : + am__include='.include' am__quote='"' ;; #( + *) : + am__include='include' am__quote='' ;; +esac ;; #( + *) : + ;; +esac + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 +$as_echo "${_am_result}" >&6; } + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar lib "link -lib" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar lib "link -lib" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 +$as_echo_n "checking the archiver ($AR) interface... " >&6; } +if ${am_cv_ar_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + am_cv_ar_interface=ar + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int some_variable = 0; +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 + (eval $am_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + am_cv_ar_interface=ar + else + am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 + (eval $am_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + am_cv_ar_interface=lib + else + am_cv_ar_interface=unknown + fi + fi + rm -f conftest.lib libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 +$as_echo "$am_cv_ar_interface" >&6; } + +case $am_cv_ar_interface in +ar) + ;; +lib) + # Microsoft lib, so override with the ar-lib wrapper script. + # FIXME: It is wrong to rewrite AR. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__AR in this case, + # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something + # similar. + AR="$am_aux_dir/ar-lib $AR" + ;; +unknown) + as_fn_error $? "could not determine $AR interface" "$LINENO" 5 + ;; +esac + + +# Requires constructor to be invoked at startup, cannot be used as static +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.4.6' +macro_revision='2.4.6' + + + + + + + + + + + + + +ltmain=$ac_aux_dir/ltmain.sh + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case $ECHO in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test yes = "$GCC"; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return, which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD=$ac_prog + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test yes = "$with_gnu_ld"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD=$ac_dir/$ac_prog + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if ${lt_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM=$NM +else + lt_nm_to_check=${ac_tool_prefix}nm + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/$lt_tmp_nm + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the 'sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS=$lt_save_ifs + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test : != "$DUMPBIN"; then + NM=$DUMPBIN + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if ${lt_cv_nm_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if ${lt_cv_sys_max_cmd_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring=ABCD + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test X`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n "$lt_cv_sys_max_cmd_len"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if ${lt_cv_ld_reload_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test yes != "$GCC"; then + reload_cmds=false + fi + ;; + darwin*) + if test yes = "$GCC"; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if ${lt_cv_deplibs_check_method+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# 'unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# that responds to the $file_magic_cmd with a given extended regex. +# If you have 'file' or equivalent on your system and you're not sure +# whether 'pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if ${lt_cv_sys_global_symbol_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test ia64 = "$host_cpu"; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 + if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS=conftstm.$ac_objext + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest$ac_exeext; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test yes = "$pipe_works"; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 +$as_echo "$with_sysroot" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 +$as_echo_n "checking for a working dd... " >&6; } +if ${ac_cv_path_lt_DD+:} false; then : + $as_echo_n "(cached) " >&6 +else + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +if test -z "$lt_DD"; then + ac_path_lt_DD_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in dd; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_lt_DD" || continue +if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi + $ac_path_lt_DD_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_lt_DD"; then + : + fi +else + ac_cv_path_lt_DD=$lt_DD +fi + +rm -f conftest.i conftest2.i conftest.out +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 +$as_echo "$ac_cv_path_lt_DD" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 +$as_echo_n "checking how to truncate binary pipes... " >&6; } +if ${lt_cv_truncate_bin+:} false; then : + $as_echo_n "(cached) " >&6 +else + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 +$as_echo "$lt_cv_truncate_bin" >&6; } + + + + + + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test no = "$enable_libtool_lock" || enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out what ABI is being produced by ac_compile, and set mode + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE=32 + ;; + *ELF-64*) + HPUX_IA64_MODE=64 + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test yes = "$lt_cv_prog_gnu_ld"; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + emul=elf + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if ${lt_cv_cc_needs_belf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks=$enable_libtool_lock + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if ${lt_cv_apple_cc_single_mod+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "$LT_MULTI_MODULE"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if ${lt_cv_ld_exported_symbols_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + 10.[012][,.]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; then + _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' + fi + if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + + +# Set options +# Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + enable_static=no +fi + + + + + + + + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + pic_mode=default +fi + + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[5-9]*,yes) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 +$as_echo_n "checking which variant of shared library versioning to provide... " >&6; } + +# Check whether --with-aix-soname was given. +if test "${with_aix_soname+set}" = set; then : + withval=$with_aix_soname; case $withval in + aix|svr4|both) + ;; + *) + as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname +else + if ${lt_cv_with_aix_soname+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_with_aix_soname=aix +fi + + with_aix_soname=$lt_cv_with_aix_soname +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 +$as_echo "$with_aix_soname" >&6; } + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS=$ltmain + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if ${lt_cv_objdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a '.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld=$lt_cv_prog_gnu_ld + +old_CC=$CC +old_CFLAGS=$CFLAGS + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +func_cc_basename $compiler +cc_basename=$func_cc_basename_result + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/${ac_tool_prefix}file"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac +fi + +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/file"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac +fi + +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC=$CC +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test yes = "$GCC"; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + + + if test yes = "$GCC"; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + lt_prog_compiler_pic='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='$wl-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64, which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if ${lt_cv_prog_compiler_pic_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test yes = "$lt_cv_prog_compiler_pic_works"; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test yes = "$lt_cv_prog_compiler_static_works"; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links=nottested +if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test no = "$hard_links"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ' (' and ')$', so one must not match beginning or + # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', + # as well as any symbol that contains 'd'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='$wl' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + export_dynamic_flag_spec='$wl--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test ia64 != "$host_cpu"; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='$wl--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + export_dynamic_flag_spec='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test linux-dietlibc = "$host_os"; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + + if test yes = "$supports_anon_versioning"; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + tcc*) + export_dynamic_flag_spec='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test no = "$ld_shlibs"; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + hardcode_direct=no + hardcode_direct_absolute=no + ;; + esac + + if test yes = "$GCC"; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + export_dynamic_flag_spec='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' $wl-bernotok' + allow_undefined_flag=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test yes = "$lt_cv_ld_force_load"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test yes = "$GCC"; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='$wl-E' + ;; + + hpux10*) + if test yes,no = "$GCC,$with_gnu_ld"; then + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='$wl-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test yes,no = "$GCC,$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test yes = "$lt_cv_prog_compiler__b"; then + archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='$wl-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test yes = "$GCC"; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo (void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test yes = "$lt_cv_irix_exported_symbol"; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + link_all_deplibs=no + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + ld_shlibs=yes + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + export_dynamic_flag_spec='$wl-E' + else + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + ;; + + osf3*) + if test yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test yes = "$GCC"; then + wlarc='$wl' + archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='$wl' + archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. GCC discards it without '$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test yes = "$GCC"; then + whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test sequent = "$host_vendor"; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='$wl-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='$wl-z,text' + allow_undefined_flag='$wl-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='$wl-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test sni = "$host_vendor"; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='$wl-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test no = "$ld_shlibs" && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test yes,yes = "$GCC,$enable_shared"; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary... + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" + elif test -n "$lt_multi_os_dir"; then + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS = " "; FS = "/|\n";} { + lt_foo = ""; + lt_count = 0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo = "/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([A-Za-z]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=.so +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + + + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='$libname$release$shared_ext$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; then + # AIX 5 supports IA64 + library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line '#! .'. This would cause the generated library to + # depend on '.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a(lib.so.V)' + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' + soname_spec='$libname$release$major$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + if test 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" + sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + hardcode_libdir_flag_spec='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) to the search path. + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec; then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' + soname_spec='$libname$shared_ext.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=sco + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test yes = "$hardcode_automatic"; then + + # We can hardcode non-existent directories. + if test no != "$hardcode_direct" && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && + test no != "$hardcode_minus_L"; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test relink = "$hardcode_action" || + test yes = "$inherit_rpath"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test yes != "$enable_dlopen"; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen=load_add_on + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen=LoadLibrary + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl +else + + lt_cv_dlopen=dyld + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : + lt_cv_dlopen=shl_load +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : + lt_cv_dlopen=dlopen +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if ${ac_cv_lib_svld_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if ${ac_cv_lib_dld_dld_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : + lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS=$LDFLAGS + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS=$LIBS + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test yes = "$cross_compiling"; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test yes = "$lt_cv_dlopen_self"; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test yes = "$cross_compiling"; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS=$save_CPPFLAGS + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP"; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report what library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC=$lt_save_CC + + + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + +# Set langage to C++ +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CXX_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + + +func_stripname_cnf () +{ + case $2 in + .*) func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%\\\\$2\$%%"`;; + *) func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%$2\$%%"`;; + esac +} # func_stripname_cnf + + if test -n "$CXX" && ( test no != "$CXX" && + ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || + (test g++ != "$CXX"))); then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +reload_flag_CXX=$reload_flag +reload_cmds_CXX=$reload_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_caught_CXX_error"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + compiler_CXX=$CC + func_cc_basename $compiler +cc_basename=$func_cc_basename_result + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test yes = "$GXX"; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test yes = "$GXX"; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test yes = "$GCC"; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return, which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD=$ac_prog + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test yes = "$with_gnu_ld"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD=$ac_dir/$ac_prog + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test yes = "$with_gnu_ld"; then + archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' + export_dynamic_flag_spec_CXX='$wl--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='$wl' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + hardcode_direct_CXX=no + hardcode_direct_absolute_CXX=no + ;; + esac + + if test yes = "$GXX"; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag=$shared_flag' $wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + export_dynamic_flag_spec_CXX='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + # The "-G" linker flag allows undefined symbols. + no_undefined_flag_CXX='-bernotok' + # Determine the default libpath from the value encoded in an empty + # executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + hardcode_libdir_flag_spec_CXX='$wl-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' $wl-bernotok' + allow_undefined_flag_CXX=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + fi + archive_cmds_need_lc_CXX=yes + archive_expsym_cmds_CXX='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared + # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. + archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_CXX=' ' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=yes + file_list_spec_CXX='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + archive_expsym_cmds_CXX='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' + enable_shared_with_static_runtimes_CXX=yes + # Don't use ranlib + old_postinstall_cmds_CXX='chmod 644 $oldlib' + postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + export_dynamic_flag_spec_CXX='$wl--export-all-symbols' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + archive_expsym_cmds_CXX='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + if test yes = "$lt_cv_ld_force_load"; then + whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec_CXX='' + fi + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + module_expsym_cmds_CXX="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + if test yes != "$lt_cv_apple_cc_single_mod"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" + archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + os2*) + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_minus_L_CXX=yes + allow_undefined_flag_CXX=unsupported + shrext_cmds=.dll + archive_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds_CXX='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes_CXX=yes + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + haiku*) + archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + link_all_deplibs_CXX=yes + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='$wl-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='$wl-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' + export_dynamic_flag_spec_CXX='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' + export_dynamic_flag_spec_CXX='$wl--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' + export_dynamic_flag_spec_CXX='$wl--export-dynamic' + whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5].* | *pgcpp\ [1-5].*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='$wl--rpath $wl$libdir' + export_dynamic_flag_spec_CXX='$wl--export-dynamic' + whole_archive_flag_spec_CXX='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' + export_dynamic_flag_spec_CXX='$wl--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + if test yes = "$supports_anon_versioning"; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='$wl-E' + whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*' + archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes,no = "$GXX,$with_gnu_ld"; then + allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test yes,no = "$GXX,$with_gnu_ld"; then + no_undefined_flag_CXX=' $wl-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + else + # g++ 2.7 appears to require '-G' NOT '-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + fi + + hardcode_libdir_flag_spec_CXX='$wl-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='$wl-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='$wl-z,text' + allow_undefined_flag_CXX='$wl-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='$wl-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ + '"$old_archive_cmds_CXX" + reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ + '"$reload_cmds_CXX" + ;; + *) + archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test no = "$ld_shlibs_CXX" && can_build_shared=no + + GCC_CXX=$GXX + LD_CXX=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $prev$p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test x-L = "$p" || + test x-R = "$p"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test no = "$pre_test_object_deps_done"; then + case $prev in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX=$prev$p + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} $prev$p" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX=$prev$p + else + postdeps_CXX="${postdeps_CXX} $prev$p" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test no = "$pre_test_object_deps_done"; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX=$p + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX=$p + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | $SED -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + + + # C++ specific cases for pic, static, wl, etc. + if test yes = "$GXX"; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + lt_prog_compiler_pic_CXX='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static_CXX='$wl-static' + ;; + esac + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='$wl-a ${wl}archive' + if test ia64 != "$host_cpu"; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='$wl-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64, which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } +lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test yes = "$lt_cv_prog_compiler_pic_works_CXX"; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test yes = "$lt_cv_prog_compiler_static_works_CXX"; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links=nottested +if test no = "$lt_cv_prog_compiler_c_o_CXX" && test no != "$need_locks"; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test no = "$hard_links"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX=$ltdll_cmds + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs_CXX=no + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test no = "$ld_shlibs_CXX" && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test yes,yes = "$GCC,$enable_shared"; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc_CXX=no + else + lt_cv_archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } + archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=.so +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + + + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='$libname$release$shared_ext$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; then + # AIX 5 supports IA64 + library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line '#! .'. This would cause the generated library to + # depend on '.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a(lib.so.V)' + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' + soname_spec='$libname$release$major$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + if test 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" + sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + hardcode_libdir_flag_spec_CXX='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) to the search path. + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec; then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' + soname_spec='$libname$shared_ext.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=sco + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test yes = "$hardcode_automatic_CXX"; then + + # We can hardcode non-existent directories. + if test no != "$hardcode_direct_CXX" && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" && + test no != "$hardcode_minus_L_CXX"; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test relink = "$hardcode_action_CXX" || + test yes = "$inherit_rpath_CXX"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test yes != "$_lt_caught_CXX_error" + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +# Checks for other programs + + +# Get compiler version and vendor +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler vendor" >&5 +$as_echo_n "checking for C++ compiler vendor... " >&6; } +if ${ax_cv_cxx_compiler_vendor+:} false; then : + $as_echo_n "(cached) " >&6 +else + # note: don't check for gcc first since some other compilers define __GNUC__ + vendors="intel: __ICC,__ECC,__INTEL_COMPILER + ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__ + pathscale: __PATHCC__,__PATHSCALE__ + clang: __clang__ + cray: _CRAYC + fujitsu: __FUJITSU + sdcc: SDCC, __SDCC + gnu: __GNUC__ + sun: __SUNPRO_C,__SUNPRO_CC + hp: __HP_cc,__HP_aCC + dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER + borland: __BORLANDC__,__CODEGEARC__,__TURBOC__ + comeau: __COMO__ + kai: __KCC + lcc: __LCC__ + sgi: __sgi,sgi + microsoft: _MSC_VER + metrowerks: __MWERKS__ + watcom: __WATCOMC__ + portland: __PGI + tcc: __TINYC__ + unknown: UNKNOWN" + for ventest in $vendors; do + case $ventest in + *:) vendor=$ventest; continue ;; + *) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;; + esac + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + #if !($vencpp) + thisisanerror; + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done + ax_cv_cxx_compiler_vendor=`echo $vendor | cut -d: -f1` + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compiler_vendor" >&5 +$as_echo "$ax_cv_cxx_compiler_vendor" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +$as_echo_n "checking for C++ compiler version... " >&6; } +if ${ax_cv_cxx_compiler_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ax_cv_cxx_compiler_vendor in #( + intel) : + if ac_fn_cxx_compute_int "$LINENO" "__INTEL_COMPILER/100" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_INTEL unknown intel compiler version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(__INTEL_COMPILER%100)/10" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_INTEL unknown intel compiler version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(__INTEL_COMPILER%10)" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_INTEL unknown intel compiler version +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + ;; #( + ibm) : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +int +main () +{ + + #if defined(__COMPILER_VER__) + choke me; + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + + if ac_fn_cxx_compute_int "$LINENO" "__xlC__/100" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_IBM unknown IBM compiler major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "__xlC__%100" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_IBM unknown IBM compiler minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "__xlC_ver__/0x100" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_IBM unknown IBM compiler patch version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "__xlC_ver__%0x100" "_ax_cxx_compiler_version_build" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_IBM unknown IBM compiler build version +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch.$_ax_cxx_compiler_version_build" + +else + + if ac_fn_cxx_compute_int "$LINENO" "__xlC__%1000" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_IBM unknown IBM compiler patch version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(__xlC__/10000)%10" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_IBM unknown IBM compiler minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(__xlC__/100000)%10" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_IBM unknown IBM compiler major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; #( + pathscale) : + + if ac_fn_cxx_compute_int "$LINENO" "__PATHCC__" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_PATHSCALE unknown pathscale major +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "__PATHCC_MINOR__" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_PATHSCALE unknown pathscale minor +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "__PATHCC_PATCHLEVEL__" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_PATHSCALE unknown pathscale patch level +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + ;; #( + clang) : + + if ac_fn_cxx_compute_int "$LINENO" "__clang_major__" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_CLANG unknown clang major +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "__clang_minor__" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_CLANG unknown clang minor +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "__clang_patchlevel__" "_ax_cxx_compiler_version_patch" ""; then : + +else + 0 +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + ;; #( + cray) : + + if ac_fn_cxx_compute_int "$LINENO" "_RELEASE" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_CRAY unknown crayc release +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "_RELEASE_MINOR" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_CRAY unknown crayc minor +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor" + ;; #( + fujitsu) : + + if ac_fn_cxx_compute_int "$LINENO" "__FCC_VERSION" "ax_cv_cxx_compiler_version" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_FUJITSUunknown fujitsu release +See \`config.log' for more details" "$LINENO" 5; } +fi + + ;; #( + gnu) : + + if ac_fn_cxx_compute_int "$LINENO" "__GNUC__" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_GNU unknown gcc major +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "__GNUC_MINOR__" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_GNU unknown gcc minor +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "__GNUC_PATCHLEVEL__" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_GNU unknown gcc patch level +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + ;; #( + sun) : + + + if ac_fn_cxx_compute_int "$LINENO" "!!( + #if defined(__SUNPRO_CC) + __SUNPRO_CC + #else + __SUNPRO_C + #endif + < 0x1000)" "_ax_cxx_compiler_version_until59" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SUN unknown sun release version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if test "X$_ax_cxx_compiler_version_until59" = X1; then : + if ac_fn_cxx_compute_int "$LINENO" " + #if defined(__SUNPRO_CC) + __SUNPRO_CC + #else + __SUNPRO_C + #endif + % 0x10" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SUN unknown sun patch version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "( + #if defined(__SUNPRO_CC) + __SUNPRO_CC + #else + __SUNPRO_C + #endif + / 0x10) % 0x10" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SUN unknown sun minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "( + #if defined(__SUNPRO_CC) + __SUNPRO_CC + #else + __SUNPRO_C + #endif + / 0x100)" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SUN unknown sun major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + +else + if ac_fn_cxx_compute_int "$LINENO" " + #if defined(__SUNPRO_CC) + __SUNPRO_CC + #else + __SUNPRO_C + #endif + % 0x10" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SUN unknown sun patch version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "( + #if defined(__SUNPRO_CC) + __SUNPRO_CC + #else + __SUNPRO_C + #endif + / 0x100) % 0x100" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SUN unknown sun minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "( + #if defined(__SUNPRO_CC) + __SUNPRO_CC + #else + __SUNPRO_C + #endif + / 0x1000)" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SUN unknown sun major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + +fi + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + ;; #( + hp) : + + + if ac_fn_cxx_compute_int "$LINENO" "!!( + #if defined(__HP_cc) + __HP_cc + #else + __HP_aCC + #endif + <= 1)" "_ax_cxx_compiler_version_untilA0121" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_HP unknown hp release version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if test "X$_ax_cxx_compiler_version_untilA0121" = X1; then : + ax_cv_cxx_compiler_version="01.21.00" + +else + if ac_fn_cxx_compute_int "$LINENO" "( + #if defined(__HP_cc) + __HP_cc + #else + __HP_aCC + #endif + % 100)" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_HP unknown hp release version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(( + #if defined(__HP_cc) + __HP_cc + #else + __HP_aCC + #endif + / 100)%100)" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_HP unknown hp minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(( + #if defined(__HP_cc) + __HP_cc + #else + __HP_aCC + #endif + / 10000)%100)" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_HP unknown hp major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + +fi + ;; #( + dec) : + + if ac_fn_cxx_compute_int "$LINENO" "( + #if defined(__DECC_VER) + __DECC_VER + #else + __DECCXX_VER + #endif + % 10000)" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_DEC unknown dec release version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(( + #if defined(__DECC_VER) + __DECC_VER + #else + __DECCXX_VER + #endif + / 100000UL)%100)" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_DEC unknown dec minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(( + #if defined(__DECC_VER) + __DECC_VER + #else + __DECCXX_VER + #endif + / 10000000UL)%100)" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_DEC unknown dec major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + ;; #( + borland) : + + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + #if defined(__TURBOC__) + __TURBOC__ + #else + choke me + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + if ac_fn_cxx_compute_int "$LINENO" " + #if defined(__TURBOC__) + __TURBOC__ + #else + choke me + #endif + " "_ax_cxx_compiler_version_turboc_raw" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_BORLAND unknown turboc version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if test $_ax_cxx_compiler_version_turboc_raw -lt 661 || test $_ax_cxx_compiler_version_turboc_raw -gt 1023; then : + if ac_fn_cxx_compute_int "$LINENO" " + #if defined(__TURBOC__) + __TURBOC__ + #else + choke me + #endif + % 0x100" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_BORLAND unknown turboc minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "( + #if defined(__TURBOC__) + __TURBOC__ + #else + choke me + #endif + /0x100)%0x100" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_BORLAND unknown turboc major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="0turboc:$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor" +else + case $_ax_cxx_compiler_version_turboc_raw in #( + 661) : + ax_cv_cxx_compiler_version="0turboc:1.00" ;; #( + 662) : + ax_cv_cxx_compiler_version="0turboc:1.01" ;; #( + 663) : + ax_cv_cxx_compiler_version="0turboc:2.00" ;; #( + *) : + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: [_AX_COMPILER_VERSION_BORLAND] unknown turboc version between 0x295 and 0x400 please report bug" >&5 +$as_echo "$as_me: WARNING: [_AX_COMPILER_VERSION_BORLAND] unknown turboc version between 0x295 and 0x400 please report bug" >&2;} + ax_cv_cxx_compiler_version="" + ;; +esac + +fi + +else + # borlandc + + if ac_fn_cxx_compute_int "$LINENO" " + #if defined(__BORLANDC__) + __BORLANDC__ + #else + __CODEGEARC__ + #endif + " "_ax_cxx_compiler_version_borlandc_raw" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_BORLAND unknown borlandc version +See \`config.log' for more details" "$LINENO" 5; } +fi + + case $_ax_cxx_compiler_version_borlandc_raw in #( + 512 ) : + ax_cv_cxx_compiler_version="1borlanc:2.00" ;; #( + 1024) : + ax_cv_cxx_compiler_version="1borlanc:3.00" ;; #( + 1024) : + ax_cv_cxx_compiler_version="1borlanc:3.00" ;; #( + 1040) : + ax_cv_cxx_compiler_version="1borlanc:3.1" ;; #( + 1106) : + ax_cv_cxx_compiler_version="1borlanc:4.0" ;; #( + 1280) : + ax_cv_cxx_compiler_version="1borlanc:5.0" ;; #( + 1312) : + ax_cv_cxx_compiler_version="1borlanc:5.02" ;; #( + 1328) : + ax_cv_cxx_compiler_version="2cppbuilder:3.0" ;; #( + 1344) : + ax_cv_cxx_compiler_version="2cppbuilder:4.0" ;; #( + 1360) : + ax_cv_cxx_compiler_version="3borlancpp:5.5" ;; #( + 1361) : + ax_cv_cxx_compiler_version="3borlancpp:5.51" ;; #( + 1378) : + ax_cv_cxx_compiler_version="3borlancpp:5.6.4" ;; #( + 1392) : + ax_cv_cxx_compiler_version="4cppbuilder:2006" ;; #( + 1424) : + ax_cv_cxx_compiler_version="4cppbuilder:2007" ;; #( + 1555) : + ax_cv_cxx_compiler_version="4cppbuilder:2009" ;; #( + 1569) : + ax_cv_cxx_compiler_version="4cppbuilder:2010" ;; #( + 1584) : + ax_cv_cxx_compiler_version="5xe" ;; #( + 1600) : + ax_cv_cxx_compiler_version="5xe:2" ;; #( + 1616) : + ax_cv_cxx_compiler_version="5xe:3" ;; #( + 1632) : + ax_cv_cxx_compiler_version="5xe:4" ;; #( + *) : + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: [_AX_COMPILER_VERSION_BORLAND] Unknown borlandc compiler version $_ax_cxx_compiler_version_borlandc_raw please report bug" >&5 +$as_echo "$as_me: WARNING: [_AX_COMPILER_VERSION_BORLAND] Unknown borlandc compiler version $_ax_cxx_compiler_version_borlandc_raw please report bug" >&2;} + ;; +esac + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; #( + comeau) : + if ac_fn_cxx_compute_int "$LINENO" "__COMO_VERSION__%100" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_COMEAU unknown comeau compiler minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(__COMO_VERSION__/100)%10" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_COMEAU unknown comeau compiler major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor" + ;; #( + kai) : + + if ac_fn_cxx_compute_int "$LINENO" "__KCC_VERSION%100" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_KAI unknown kay compiler patch version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(__KCC_VERSION/100)%10" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_KAI unknown kay compiler minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(__KCC_VERSION/1000)%10" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_KAI unknown kay compiler major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + ;; #( + sgi) : + + + if ac_fn_cxx_compute_int "$LINENO" " + #if defined(_COMPILER_VERSION) + _COMPILER_VERSION + #else + _SGI_COMPILER_VERSION + #endif + %10" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SGI unknown SGI compiler patch version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "( + #if defined(_COMPILER_VERSION) + _COMPILER_VERSION + #else + _SGI_COMPILER_VERSION + #endif + /10)%10" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SGI unknown SGI compiler minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "( + #if defined(_COMPILER_VERSION) + _COMPILER_VERSION + #else + _SGI_COMPILER_VERSION + #endif + /100)%10" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SGI unknown SGI compiler major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + ;; #( + microsoft) : + + if ac_fn_cxx_compute_int "$LINENO" "_MSC_VER%100" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_MICROSOFT unknown microsoft compiler minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(_MSC_VER/100)%100" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_MICROSOFT unknown microsoft compiler major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + _ax_cxx_compiler_version_patch=0 + _ax_cxx_compiler_version_build=0 + # special case for version 6 + if test "X$_ax_cxx_compiler_version_major" = "X12"; then : + if ac_fn_cxx_compute_int "$LINENO" "_MSC_FULL_VER%1000" "_ax_cxx_compiler_version_patch" ""; then : + +else + _ax_cxx_compiler_version_patch=0 +fi + +fi + # for version 7 + if test "X$_ax_cxx_compiler_version_major" = "X13"; then : + if ac_fn_cxx_compute_int "$LINENO" "_MSC_FULL_VER%1000" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_MICROSOFT unknown microsoft compiler patch version +See \`config.log' for more details" "$LINENO" 5; } +fi + + +fi + # for version > 8 + if test $_ax_cxx_compiler_version_major -ge 14; then : + if ac_fn_cxx_compute_int "$LINENO" "_MSC_FULL_VER%10000" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_MICROSOFT unknown microsoft compiler patch version +See \`config.log' for more details" "$LINENO" 5; } +fi + + +fi + if test $_ax_cxx_compiler_version_major -ge 15; then : + if ac_fn_cxx_compute_int "$LINENO" "_MSC_BUILD" "_ax_cxx_compiler_version_build" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_MICROSOFT unknown microsoft compiler build version +See \`config.log' for more details" "$LINENO" 5; } +fi + + +fi + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch.$_ax_cxx_compiler_version_build" + ;; #( + metrowerks) : + if ac_fn_cxx_compute_int "$LINENO" "__MWERKS__%0x100" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_METROWERKS unknown metrowerks compiler patch version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(__MWERKS__/0x100)%0x10" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_METROWERKS unknown metrowerks compiler minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(__MWERKS__/0x1000)%0x10" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_METROWERKS unknown metrowerks compiler major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + ;; #( + watcom) : + if ac_fn_cxx_compute_int "$LINENO" "__WATCOMC__%100" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_WATCOM unknown watcom compiler minor version +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "(__WATCOMC__/100)%100" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_WATCOM unknown watcom compiler major version +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor" + ;; #( + portland) : + + if ac_fn_cxx_compute_int "$LINENO" "__PGIC__" "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_PORTLAND unknown pgi major +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "__PGIC_MINOR__" "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_PORTLAND unknown pgi minor +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "__PGIC_PATCHLEVEL__" "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_PORTLAND unknown pgi patch level +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + ;; #( + tcc) : + + ax_cv_cxx_compiler_version=`tcc -v | $SED 's/^[ ]*tcc[ ]\+version[ ]\+\([0-9.]\+\).*/\1/g'` + ;; #( + sdcc) : + + if ac_fn_cxx_compute_int "$LINENO" "/* avoid parse error with comments */ + #if(defined(__SDCC_VERSION_MAJOR)) + __SDCC_VERSION_MAJOR + #else + SDCC/100 + #endif + " "_ax_cxx_compiler_version_major" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SDCC unknown sdcc major +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" "/* avoid parse error with comments */ + #if(defined(__SDCC_VERSION_MINOR)) + __SDCC_VERSION_MINOR + #else + (SDCC%100)/10 + #endif + " "_ax_cxx_compiler_version_minor" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SDCC unknown sdcc minor +See \`config.log' for more details" "$LINENO" 5; } +fi + + if ac_fn_cxx_compute_int "$LINENO" " + /* avoid parse error with comments */ + #if(defined(__SDCC_VERSION_PATCH)) + __SDCC_VERSION_PATCH + #elsif(defined(_SDCC_VERSION_PATCHLEVEL)) + __SDCC_VERSION_PATCHLEVEL + #else + SDCC%10 + #endif + " "_ax_cxx_compiler_version_patch" ""; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "_AX_COMPILER_VERSION_SDCC unknown sdcc patch level +See \`config.log' for more details" "$LINENO" 5; } +fi + + ax_cv_cxx_compiler_version="$_ax_cxx_compiler_version_major.$_ax_cxx_compiler_version_minor.$_ax_cxx_compiler_version_patch" + ;; #( + *) : + ax_cv_cxx_compiler_version="" ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compiler_version" >&5 +$as_echo "$ax_cv_cxx_compiler_version" >&6; } + + + + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + + ax_compare_version_A=`echo "$ax_cv_cxx_compiler_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + ax_compare_version_B=`echo "11" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ + -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ + -e 's/[^0-9]//g'` + + + + # A count greater than zero means use only that many subversions + ax_compare_version_A=`echo "$ax_compare_version_A" | sed "s/\(\([0-9]\{4\}\)\{1\}\).*/\1/"` + ax_compare_version_B=`echo "$ax_compare_version_B" | sed "s/\(\([0-9]\{4\}\)\{1\}\).*/\1/"` + + + # Pad zeros at end of numbers to make same length. + ax_compare_version_tmp_A="$ax_compare_version_A`echo $ax_compare_version_B | sed 's/./0/g'`" + ax_compare_version_B="$ax_compare_version_B`echo $ax_compare_version_A | sed 's/./0/g'`" + ax_compare_version_A="$ax_compare_version_tmp_A" + + # Check for equality or inequality as necessary. + + test "x$ax_compare_version_A" = "x$ax_compare_version_B" && ax_compare_version=true + + + + + if test "$ax_compare_version" = "true" ; then + cxx_compiler_version_11="yes" + fi + + +# Checks for compiler support + ax_cxx_compile_alternatives="14 1y" ax_cxx_compile_cxx14_required=true + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + ac_success=no + + + + + + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=`$as_echo "ax_cv_cxx_compile_cxx14_$switch" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++14 features with $switch" >&5 +$as_echo_n "checking whether $CXX supports C++14 features with $switch... " >&6; } +if eval \${$cachevar+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CXX="$CXX" + CXX="$CXX $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} + }; + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval $cachevar=yes +else + eval $cachevar=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXX="$ac_save_CXX" +fi +eval ac_res=\$$cachevar + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + if test x$ax_cxx_compile_cxx14_required = xtrue; then + if test x$ac_success = xno; then + as_fn_error $? "*** A compiler with support for C++14 language features is required." "$LINENO" 5 + fi + fi + if test x$ac_success = xno; then + HAVE_CXX14=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++14 support was found" >&5 +$as_echo "$as_me: No compiler with C++14 support was found" >&6;} + else + HAVE_CXX14=1 + +$as_echo "#define HAVE_CXX14 1" >>confdefs.h + + fi + + + ax_cxx_compile_alternatives="17 1z" ax_cxx_compile_cxx17_required=false + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + ac_success=no + + + + + + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=`$as_echo "ax_cv_cxx_compile_cxx17_$switch" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++17 features with $switch" >&5 +$as_echo_n "checking whether $CXX supports C++17 features with $switch... " >&6; } +if eval \${$cachevar+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CXX="$CXX" + CXX="$CXX $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} + }; + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + + + + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201703L + +#error "This is not a C++17 compiler" + +#else + +#include +#include +#include + +namespace cxx17 +{ + + namespace test_constexpr_lambdas + { + + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) + { + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + + namespace test_template_argument_deduction_for_class_templates + { + + template + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } + + namespace test_non_type_auto_template_parameters + { + + template + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + + namespace test_structured_bindings + { + + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] + { + return arr; + } + + auto f2() -> std::pair& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } + + namespace test_exception_spec_type_system + { + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template + Bad + f(T*, T*); + + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); + + } + + namespace test_inline_variables + { + + template void f(T) + {} + + template inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus < 201703L + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval $cachevar=yes +else + eval $cachevar=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXX="$ac_save_CXX" +fi +eval ac_res=\$$cachevar + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + if test x$ax_cxx_compile_cxx17_required = xtrue; then + if test x$ac_success = xno; then + as_fn_error $? "*** A compiler with support for C++17 language features is required." "$LINENO" 5 + fi + fi + if test x$ac_success = xno; then + HAVE_CXX17=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++17 support was found" >&5 +$as_echo "$as_me: No compiler with C++17 support was found" >&6;} + else + HAVE_CXX17=1 + +$as_echo "#define HAVE_CXX17 1" >>confdefs.h + + fi + + +if test "x$ax_cv_cxx_compiler_vendor" = x"clang" && test "x$cxx_compiler_version_11" = x"yes"; then : + + # Clang 11 crashes when compiling with -std=c++20 + +else + + ax_cxx_compile_alternatives="20" ax_cxx_compile_cxx20_required=false + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + ac_success=no + + + + + + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=`$as_echo "ax_cv_cxx_compile_cxx20_$switch" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++20 features with $switch" >&5 +$as_echo_n "checking whether $CXX supports C++20 features with $switch... " >&6; } +if eval \${$cachevar+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CXX="$CXX" + CXX="$CXX $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} + }; + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + + + + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201703L + +#error "This is not a C++17 compiler" + +#else + +#include +#include +#include + +namespace cxx17 +{ + + namespace test_constexpr_lambdas + { + + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) + { + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + + namespace test_template_argument_deduction_for_class_templates + { + + template + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } + + namespace test_non_type_auto_template_parameters + { + + template + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + + namespace test_structured_bindings + { + + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] + { + return arr; + } + + auto f2() -> std::pair& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } + + namespace test_exception_spec_type_system + { + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template + Bad + f(T*, T*); + + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); + + } + + namespace test_inline_variables + { + + template void f(T) + {} + + template inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus < 201703L + + + + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 202002L + +#error "This is not a C++20 compiler" + +#else + +#include + +namespace cxx20 +{ + +// As C++20 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx20 + +#endif // __cplusplus < 202002L + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval $cachevar=yes +else + eval $cachevar=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXX="$ac_save_CXX" +fi +eval ac_res=\$$cachevar + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + if test x$ax_cxx_compile_cxx20_required = xtrue; then + if test x$ac_success = xno; then + as_fn_error $? "*** A compiler with support for C++20 language features is required." "$LINENO" 5 + fi + fi + if test x$ac_success = xno; then + HAVE_CXX20=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++20 support was found" >&5 +$as_echo "$as_me: No compiler with C++20 support was found" >&6;} + else + HAVE_CXX20=1 + +$as_echo "#define HAVE_CXX20 1" >>confdefs.h + + fi + + + +fi + +# If available, use -fvisibility=hidden to hide internal names + + + + +for flag in -fvisibility=hidden; do + as_CACHEVAR=`$as_echo "ax_cv_check_cxxflags__$flag" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $flag" >&5 +$as_echo_n "checking whether C++ compiler accepts $flag... " >&6; } +if eval \${$as_CACHEVAR+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CXXFLAGS + CXXFLAGS="$CXXFLAGS $flag" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval "$as_CACHEVAR=yes" +else + eval "$as_CACHEVAR=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXXFLAGS=$ax_check_save_flags +fi +eval ac_res=\$$as_CACHEVAR + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then : + +if ${CXXFLAGS+:} false; then : + + case " $CXXFLAGS " in #( + *" $flag "*) : + { { $as_echo "$as_me:${as_lineno-$LINENO}: : CXXFLAGS already contains \$flag"; } >&5 + (: CXXFLAGS already contains $flag) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } ;; #( + *) : + + as_fn_append CXXFLAGS " $flag" + { { $as_echo "$as_me:${as_lineno-$LINENO}: : CXXFLAGS=\"\$CXXFLAGS\""; } >&5 + (: CXXFLAGS="$CXXFLAGS") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + ;; +esac + +else + + CXXFLAGS=$flag + { { $as_echo "$as_me:${as_lineno-$LINENO}: : CXXFLAGS=\"\$CXXFLAGS\""; } >&5 + (: CXXFLAGS="$CXXFLAGS") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + +fi + +else + : +fi + +done + + +# If available, use -zdefs to improve linker consistency + + + + +for flag in -Wl,-z,defs; do + as_CACHEVAR=`$as_echo "ax_cv_check_ldflags__$flag" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts $flag" >&5 +$as_echo_n "checking whether the linker accepts $flag... " >&6; } +if eval \${$as_CACHEVAR+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$LDFLAGS + LDFLAGS="$LDFLAGS $flag" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + eval "$as_CACHEVAR=yes" +else + eval "$as_CACHEVAR=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$ax_check_save_flags +fi +eval ac_res=\$$as_CACHEVAR + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then : + +if ${LDFLAGS+:} false; then : + + case " $LDFLAGS " in #( + *" $flag "*) : + { { $as_echo "$as_me:${as_lineno-$LINENO}: : LDFLAGS already contains \$flag"; } >&5 + (: LDFLAGS already contains $flag) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } ;; #( + *) : + + as_fn_append LDFLAGS " $flag" + { { $as_echo "$as_me:${as_lineno-$LINENO}: : LDFLAGS=\"\$LDFLAGS\""; } >&5 + (: LDFLAGS="$LDFLAGS") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + ;; +esac + +else + + LDFLAGS=$flag + { { $as_echo "$as_me:${as_lineno-$LINENO}: : LDFLAGS=\"\$LDFLAGS\""; } >&5 + (: LDFLAGS="$LDFLAGS") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + +fi + +else + : +fi + +done + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ax_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on Tru64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + if test "x$PTHREAD_CC" != "x"; then : + CC="$PTHREAD_CC" +fi + if test "x$PTHREAD_CXX" != "x"; then : + CXX="$PTHREAD_CXX" +fi + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS" >&5 +$as_echo_n "checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_join (); +int +main () +{ +return pthread_join (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_pthread_ok=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +$as_echo "$ax_pthread_ok" >&6; } + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items with a "," contain both +# C compiler flags (before ",") and linker flags (after ","). Other items +# starting with a "-" are C compiler flags, and remaining items are +# library names, except for "none" which indicates that we try without +# any flags at all, and "pthread-config" which is a program returning +# the flags for the Pth emulation library. + +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5 +$as_echo "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;} +fi +rm -f conftest* + + ;; + + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags" + ;; +esac + +# Are we compiling with Clang? + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC is Clang" >&5 +$as_echo_n "checking whether $CC is Clang... " >&6; } +if ${ax_cv_PTHREAD_CLANG+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1; then : + ax_cv_PTHREAD_CLANG=yes +fi +rm -f conftest* + + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5 +$as_echo "$ax_cv_PTHREAD_CLANG" >&6; } +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +# Note that for GCC and Clang -pthread generally implies -lpthread, +# except when -nostdlib is passed. +# This is problematic using libtool to build C++ shared libraries with pthread: +# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460 +# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333 +# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555 +# To solve this, first try -pthread together with -lpthread for GCC + +if test "x$GCC" = "xyes"; then : + ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags" +fi + +# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first + +if test "x$ax_pthread_clang" = "xyes"; then : + ax_pthread_flags="-pthread,-lpthread -pthread" +fi + + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" + ;; +esac +if test "x$ax_pthread_check_macro" = "x--"; then : + ax_pthread_check_cond=0 +else + ax_pthread_check_cond="!defined($ax_pthread_check_macro)" +fi + + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 +$as_echo_n "checking whether pthreads work without any flags... " >&6; } + ;; + + *,*) + PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"` + PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with \"$PTHREAD_CFLAGS\" and \"$PTHREAD_LIBS\"" >&5 +$as_echo_n "checking whether pthreads work with \"$PTHREAD_CFLAGS\" and \"$PTHREAD_LIBS\"... " >&6; } + ;; + + -*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $ax_pthread_try_flag" >&5 +$as_echo_n "checking whether pthreads work with $ax_pthread_try_flag... " >&6; } + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + # Extract the first word of "pthread-config", so it can be a program name with args. +set dummy pthread-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ax_pthread_config+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ax_pthread_config"; then + ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ax_pthread_config="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no" +fi +fi +ax_pthread_config=$ac_cv_prog_ax_pthread_config +if test -n "$ax_pthread_config"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5 +$as_echo "$ax_pthread_config" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$ax_pthread_config" = "xno"; then : + continue +fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$ax_pthread_try_flag" >&5 +$as_echo_n "checking for the pthreads library -l$ax_pthread_try_flag... " >&6; } + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void *some_global = NULL; + static void routine(void *a) + { + /* To avoid any unused-parameter or + unused-but-set-parameter warning. */ + some_global = a; + } + static void *start_routine(void *a) { return a; } +int +main () +{ +pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */ + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_pthread_ok=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +$as_echo "$ax_pthread_ok" >&6; } + if test "x$ax_pthread_ok" = "xyes"; then : + break +fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread" >&5 +$as_echo_n "checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread... " >&6; } +if ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + if test "x$ax_pthread_try" = "xunknown"; then : + break +fi + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void){return 0;} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_link="$ax_pthread_2step_ac_link" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void){return 0;} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + if test "x$ax_pthread_try" = "x"; then : + ax_pthread_try=no +fi + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5 +$as_echo "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; } + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + + + +# Various other checks: +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 +$as_echo_n "checking for joinable pthread attribute... " >&6; } +if ${ax_cv_PTHREAD_JOINABLE_ATTR+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int attr = $ax_pthread_attr; return attr /* ; */ + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5 +$as_echo "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; } + if test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"; then : + +cat >>confdefs.h <<_ACEOF +#define PTHREAD_CREATE_JOINABLE $ax_cv_PTHREAD_JOINABLE_ATTR +_ACEOF + + ax_pthread_joinable_attr_defined=yes + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether more special flags are required for pthreads" >&5 +$as_echo_n "checking whether more special flags are required for pthreads... " >&6; } +if ${ax_cv_PTHREAD_SPECIAL_FLAGS+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5 +$as_echo "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; } + if test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"; then : + PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5 +$as_echo_n "checking for PTHREAD_PRIO_INHERIT... " >&6; } +if ${ax_cv_PTHREAD_PRIO_INHERIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int i = PTHREAD_PRIO_INHERIT; + return i; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_cv_PTHREAD_PRIO_INHERIT=yes +else + ax_cv_PTHREAD_PRIO_INHERIT=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5 +$as_echo "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; } + if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"; then : + +$as_echo "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h + + ax_pthread_prio_inherit_defined=yes + +fi + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + case "x/$CC" in #( + x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) : + #handle absolute path differently from PATH based program lookup + case "x$CC" in #( + x/*) : + + if as_fn_executable_p ${CC}_r; then : + PTHREAD_CC="${CC}_r" +fi + if test "x${CXX}" != "x"; then : + if as_fn_executable_p ${CXX}_r; then : + PTHREAD_CXX="${CXX}_r" +fi +fi + ;; #( + *) : + + for ac_prog in ${CC}_r +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PTHREAD_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PTHREAD_CC"; then + ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PTHREAD_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +PTHREAD_CC=$ac_cv_prog_PTHREAD_CC +if test -n "$PTHREAD_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 +$as_echo "$PTHREAD_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$PTHREAD_CC" && break +done +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + + if test "x${CXX}" != "x"; then : + for ac_prog in ${CXX}_r +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PTHREAD_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PTHREAD_CXX"; then + ac_cv_prog_PTHREAD_CXX="$PTHREAD_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PTHREAD_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +PTHREAD_CXX=$ac_cv_prog_PTHREAD_CXX +if test -n "$PTHREAD_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CXX" >&5 +$as_echo "$PTHREAD_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$PTHREAD_CXX" && break +done +test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" + +fi + + ;; +esac + ;; #( + *) : + ;; +esac + ;; + esac + fi +fi + +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" +test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" + + + + + + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "x$ax_pthread_ok" = "xyes"; then + +$as_echo "#define HAVE_PTHREAD 1" >>confdefs.h + + : +else + ax_pthread_ok=no + as_fn_error $? "pthread required." "$LINENO" 5 +fi +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + +# Add support for --disable-assert + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable assertions" >&5 +$as_echo_n "checking whether to enable assertions... " >&6; } + # Check whether --enable-assert was given. +if test "${enable_assert+set}" = set; then : + enableval=$enable_assert; ac_enable_assert=$enableval + if test "x$enableval" = xno; then : + +$as_echo "#define NDEBUG 1" >>confdefs.h + +elif test "x$enableval" != xyes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: invalid argument supplied to --enable-assert" >&5 +$as_echo "$as_me: WARNING: invalid argument supplied to --enable-assert" >&2;} + ac_enable_assert=yes +fi +else + ac_enable_assert=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_enable_assert" >&5 +$as_echo "$ac_enable_assert" >&6; } + + +# Defines +$as_echo "#define BOOST_ERROR_CODE_HEADER_ONLY /**/" >>confdefs.h + +$as_echo "#define BOOST_SYSTEM_NO_DEPRECATED /**/" >>confdefs.h + +$as_echo "#define BOOST_ENABLE_ASSERT_DEBUG_HANDLER /**/" >>confdefs.h + + +# This define disables support for 128-bit integers on fmt, currently unused by this +# program. This is required to fix build pipelines running on new Clang conan-io images. +# The issue seems related to GNU Libtool not adding a shared object to resolve __udivti3, +# when building in new images like conanio/clang14-ubuntu16.04, while is works on old +# images like conanio/clang9. Alternatively, it could be fixed also by adding -lgcc manually. +# Hopefully this workaround may also fix build issues on some other configurations. +$as_echo "#define FMT_USE_INT128 0" >>confdefs.h + + +# Check headers + +ac_fn_cxx_check_header_mongrel "$LINENO" "CAEN_FELib.h" "ac_cv_header_CAEN_FELib_h" "$ac_includes_default" +if test "x$ac_cv_header_CAEN_FELib_h" = xyes; then : + +else + as_fn_error $? "CAEN_FELib.h required." "$LINENO" 5 +fi + + + +# Checks for Boost 1.67.0 or greater + + +# Check whether --with-boost was given. +if test "${with_boost+set}" = set; then : + withval=$with_boost; + case $withval in #( + no) : + want_boost="no";_AX_BOOST_BASE_boost_path="" ;; #( + yes) : + want_boost="yes";_AX_BOOST_BASE_boost_path="" ;; #( + *) : + want_boost="yes";_AX_BOOST_BASE_boost_path="$withval" ;; +esac + +else + want_boost="yes" +fi + + + + +# Check whether --with-boost-libdir was given. +if test "${with_boost_libdir+set}" = set; then : + withval=$with_boost_libdir; + if test -d "$withval"; then : + _AX_BOOST_BASE_boost_lib_path="$withval" +else + as_fn_error $? "--with-boost-libdir expected directory name" "$LINENO" 5 +fi + +else + _AX_BOOST_BASE_boost_lib_path="" +fi + + +BOOST_LDFLAGS="" +BOOST_CPPFLAGS="" +if test "x$want_boost" = "xyes"; then : + + + if test "x1.67.0" = "x"; then : + _AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0" +else + _AX_BOOST_BASE_TONUMERICVERSION_req="1.67.0" +fi + _AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([0-9]*\.[0-9]*\)'` + _AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([0-9]*\)'` + if test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"; then : + as_fn_error $? "You should at least specify libboost major version" "$LINENO" 5 +fi + _AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[0-9]*\.\([0-9]*\)'` + if test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"; then : + _AX_BOOST_BASE_TONUMERICVERSION_req_minor="0" +fi + _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[0-9]*\.[0-9]*\.\([0-9]*\)'` + if test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"; then : + _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0" +fi + _AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor` + WANT_BOOST_VERSION=$_AX_BOOST_BASE_TONUMERICVERSION_RET + + succeeded=no + + + + case ${host_cpu} in #( + x86_64) : + libsubdirs="lib64 libx32 lib lib64" ;; #( + ppc64|s390x|sparc64|aarch64|ppc64le) : + libsubdirs="lib64 lib lib64" ;; #( + *) : + libsubdirs="lib" + ;; +esac + + case ${host_cpu} in #( + i?86) : + multiarch_libsubdir="lib/i386-${host_os}" ;; #( + *) : + multiarch_libsubdir="lib/${host_cpu}-${host_os}" + ;; +esac + + if test "x$_AX_BOOST_BASE_boost_path" != "x"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for boostlib >= 1.67.0 ($WANT_BOOST_VERSION) includes in \"$_AX_BOOST_BASE_boost_path/include\"" >&5 +$as_echo_n "checking for boostlib >= 1.67.0 ($WANT_BOOST_VERSION) includes in \"$_AX_BOOST_BASE_boost_path/include\"... " >&6; } + if test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include" + for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for boostlib >= 1.67.0 ($WANT_BOOST_VERSION) lib path in \"$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp\"" >&5 +$as_echo_n "checking for boostlib >= 1.67.0 ($WANT_BOOST_VERSION) lib path in \"$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp\"... " >&6; } + if test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"; + break; + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + done +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +else + + if test X"$cross_compiling" = Xyes; then + search_libsubdirs=$multiarch_libsubdir + else + search_libsubdirs="$multiarch_libsubdir $libsubdirs" + fi + for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then + for libsubdir in $search_libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir" + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include" + break; + fi + done + +fi + + if test "x$_AX_BOOST_BASE_boost_lib_path" != "x"; then : + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for boostlib >= 1.67.0 ($WANT_BOOST_VERSION)" >&5 +$as_echo_n "checking for boostlib >= 1.67.0 ($WANT_BOOST_VERSION)... " >&6; } + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main () +{ + +(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($WANT_BOOST_VERSION))])); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + succeeded=yes + found_system=yes + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + + + if test "x$succeeded" != "xyes" ; then + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + BOOST_CPPFLAGS= + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + BOOST_LDFLAGS= + fi + _version=0 + if test -n "$_AX_BOOST_BASE_boost_path" ; then + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "x$V_CHECK" = "x1" ; then + _version=$_version_tmp + fi + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE" + done + if test -z "$BOOST_CPPFLAGS"; then + if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path" + fi + fi + if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then + for libsubdir in $libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir" + fi + fi + else + if test "x$cross_compiling" != "xyes" ; then + for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "x$V_CHECK" = "x1" ; then + _version=$_version_tmp + best_path=$_AX_BOOST_BASE_boost_path + fi + done + fi + done + + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + for libsubdir in $libsubdirs ; do + if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$best_path/$libsubdir" + fi + fi + + if test -n "$BOOST_ROOT" ; then + for libsubdir in $libsubdirs ; do + if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then + version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` + stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` + stage_version_shorten=`expr $stage_version : '\([0-9]*\.[0-9]*\)'` + V_CHECK=`expr $stage_version_shorten \>\= $_version` + if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: We will use a staged boost library from $BOOST_ROOT" >&5 +$as_echo "$as_me: We will use a staged boost library from $BOOST_ROOT" >&6;} + BOOST_CPPFLAGS="-I$BOOST_ROOT" + BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir" + fi + fi + fi + fi + + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main () +{ + +(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($WANT_BOOST_VERSION))])); + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + succeeded=yes + found_system=yes + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + fi + + if test "x$succeeded" != "xyes" ; then + if test "x$_version" = "x0" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: We could not detect the boost libraries (version 1.67.0 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation." >&5 +$as_echo "$as_me: We could not detect the boost libraries (version 1.67.0 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation." >&6;} + else + { $as_echo "$as_me:${as_lineno-$LINENO}: Your boost libraries seems to old (version $_version)." >&5 +$as_echo "$as_me: Your boost libraries seems to old (version $_version)." >&6;} + fi + # execute ACTION-IF-NOT-FOUND (if present): + as_fn_error $? "Boost library >= 1.67.0 (headers only) required." "$LINENO" 5 + else + +$as_echo "#define HAVE_BOOST /**/" >>confdefs.h + + # execute ACTION-IF-FOUND (if present): + : + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + + +fi + + + + +ac_config_files="$ac_config_files Makefile src/Makefile" + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by CAEN_Dig2 $as_me v1.6.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +CAEN_Dig2 config.status v1.6.1 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' +configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' +predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' +predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' +postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' +reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' +reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_import \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +lt_cv_nm_interface \ +nm_file_list_spec \ +lt_cv_truncate_bin \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +reload_flag_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_separator_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +configure_time_dlsearch_path \ +configure_time_lt_sys_library_path \ +reload_cmds_CXX \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX \ +postlink_cmds_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' + +# See if we are running on zsh, and set the options that allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + RM='$RM' + ofile='$ofile' + + + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + case $CONFIG_FILES in #( + *\'*) : + eval set x "$CONFIG_FILES" ;; #( + *) : + set x $CONFIG_FILES ;; #( + *) : + ;; +esac + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`$as_dirname -- "$am_mf" || +$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$am_mf" : 'X\(//\)[^/]' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$am_mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + am_filepart=`$as_basename -- "$am_mf" || +$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$am_mf" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { echo "$as_me:$LINENO: cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles" >&5 + (cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } || am_rc=$? + done + if test $am_rc -ne 0; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. Try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking). +See \`config.log' for more details" "$LINENO" 5; } + fi + { am_dirpart=; unset am_dirpart;} + { am_filepart=; unset am_filepart;} + { am_mf=; unset am_mf;} + { am_rc=; unset am_rc;} + rm -f conftest-deps.mk +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options that allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST + fi + + cfgfile=${ofile}T + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL +# Generated automatically by $as_me ($PACKAGE) $VERSION +# NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +# Copyright (C) 2014 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program or library that is built +# using GNU Libtool, you may include this file under the same +# distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# The names of the tagged configurations supported by this script. +available_tags='CXX ' + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shared archive member basename,for filename based shared library versioning on AIX. +shared_archive_member_spec=$shared_archive_member_spec + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm into a list of symbols to manually relocate. +global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name lister interface. +nm_interface=$lt_lt_cv_nm_interface + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and where our libraries should be installed. +lt_sysroot=$lt_sysroot + +# Command to truncate a binary pipe. +lt_truncate_bin=$lt_lt_cv_truncate_bin + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Detected run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path + +# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. +configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \$shlibpath_var if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain=$ac_aux_dir/ltmain.sh + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \$shlibpath_var if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..37535e8 --- /dev/null +++ b/configure.ac @@ -0,0 +1,94 @@ +# Copyright (C) 2020-2023 CAEN SpA +# +# This file is part of the CAEN Dig2 Library. +# +# The CAEN Dig2 Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# The CAEN Dig2 Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the CAEN Dig2 Library; if not, see +# https://www.gnu.org/licenses/. +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +# Tested with autoconf 2.69, released in 2012 +AC_PREREQ([2.69]) +AC_INIT(CAEN_Dig2, [m4_esyscmd_s([echo $VERSION])], support.computing@caen.it) + +# Search in m4 folder for custom macros. It requires also ACLOCAL_AMFLAGS on +# Makefile.am, unless we use AC_CONFIG_MACRO_DIRS introduced on autoconf 2.70. +AC_CONFIG_MACRO_DIR([m4]) + +# tar-ustar required to remove the filename length limit on default tar-v7 format +# is old enough to be supported everywhere +AM_INIT_AUTOMAKE([-Wall foreign subdir-objects tar-ustar]) +AM_PROG_AR + +# Requires constructor to be invoked at startup, cannot be used as static +LT_INIT([disable-static]) + +# Set langage to C++ +AC_PROG_CXX +AC_LANG([C++]) + +# Checks for other programs +AC_PROG_INSTALL + +# Get compiler version and vendor +AX_COMPILER_VENDOR +AX_COMPILER_VERSION +AX_COMPARE_VERSION([$ax_cv_cxx_compiler_version], [eq1], [11], [cxx_compiler_version_11="yes"]) + +# Checks for compiler support +AX_CXX_COMPILE_STDCXX([14], [noext], [mandatory]) +AX_CXX_COMPILE_STDCXX([17], [noext], [optional]) +AS_IF( +[test "x$ax_cv_cxx_compiler_vendor" = x"clang" && test "x$cxx_compiler_version_11" = x"yes"], [ + # Clang 11 crashes when compiling with -std=c++20 +], [ + AX_CXX_COMPILE_STDCXX([20], [noext], [optional]) +]) + +# If available, use -fvisibility=hidden to hide internal names +AX_APPEND_COMPILE_FLAGS([-fvisibility=hidden]) + +# If available, use -zdefs to improve linker consistency +AX_APPEND_LINK_FLAGS([-Wl,-z,defs]) + +AX_PTHREAD([], [AC_MSG_ERROR([pthread required.])]) + +# Add support for --disable-assert +AC_HEADER_ASSERT + +# Defines +AC_DEFINE([BOOST_ERROR_CODE_HEADER_ONLY], []) +AC_DEFINE([BOOST_SYSTEM_NO_DEPRECATED], []) +AC_DEFINE([BOOST_ENABLE_ASSERT_DEBUG_HANDLER], []) + +# This define disables support for 128-bit integers on fmt, currently unused by this +# program. This is required to fix build pipelines running on new Clang conan-io images. +# The issue seems related to GNU Libtool not adding a shared object to resolve __udivti3, +# when building in new images like conanio/clang14-ubuntu16.04, while is works on old +# images like conanio/clang9. Alternatively, it could be fixed also by adding -lgcc manually. +# Hopefully this workaround may also fix build issues on some other configurations. +AC_DEFINE([FMT_USE_INT128], [0]) + +# Check headers +AC_CHECK_HEADER([CAEN_FELib.h], [], [AC_MSG_ERROR(CAEN_FELib.h required.)]) + +# Checks for Boost 1.67.0 or greater +AX_BOOST_BASE([1.67.0], [], [AC_MSG_ERROR(Boost library >= 1.67.0 (headers only) required.)]) + +AC_CONFIG_FILES([ + Makefile + src/Makefile +]) + +AC_OUTPUT diff --git a/demo/caen-felib-demo-dpp-pha/Makefile b/demo/caen-felib-demo-dpp-pha/Makefile new file mode 100644 index 0000000..67eacd1 --- /dev/null +++ b/demo/caen-felib-demo-dpp-pha/Makefile @@ -0,0 +1,20 @@ +TARGET = caen-felib-demo-dpp-pha +CFLAGS = -std=gnu11 -O2 -g -Wall -pthread +LDFLAGS = -pthread +LDLIBS = -lpthread -lCAEN_FELib + +.PHONY: default all clean + +default: $(TARGET) +all: default + +OBJECTS = main.o + +.PRECIOUS: $(TARGET) $(OBJECTS) + +$(TARGET): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $@ + +clean: + -rm -f *.o + -rm -f $(TARGET) diff --git a/demo/caen-felib-demo-dpp-pha/c11threads.h b/demo/caen-felib-demo-dpp-pha/c11threads.h new file mode 100644 index 0000000..cccf430 --- /dev/null +++ b/demo/caen-felib-demo-dpp-pha/c11threads.h @@ -0,0 +1,533 @@ +/* +c11threads + +Authors: + John Tsiombikas - original POSIX threads wrapper + Oliver Old - win32 implementation + +I place this piece of code in the public domain. Feel free to use as you see +fit. I'd appreciate it if you keep my name at the top of the code somewhere, but +whatever. + +Main project site: https://github.com/jtsiomb/c11threads +*/ +#ifndef C11THREADS_H_ +#define C11THREADS_H_ + +/* If you wish to use this with pthread-win32 (i.e. use the POSIX threads wrapper + * instead of the native win32 API implementation of C11 threads), then just + * define C11THREADS_PTHREAD_WIN32 before including this header file. + */ +#if defined(_WIN32) && !defined(C11THREADS_PTHREAD_WIN32) +#define C11THREADS_WIN32 +#endif + +/* If your compiler does not support the inline keyword, or supports it with + * some different variation of prefix or suffix underscores, you can define + * C11THREADS_INLINE before including this header file. + */ +#ifndef C11THREADS_INLINE +/* C99 compilers will have inline */ +#if __STDC_VERSION__ >= 199901L +#define C11THREADS_INLINE inline +/* C++ has inline */ +#elif defined(__cplusplus) +#define C11THREADS_INLINE inline +/* MSVC has inline from VS 2015 but supports __inline in older versions */ +#elif defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define C11THREADS_INLINE inline +#else +#define C11THREADS_INLINE __inline +#endif +/* for every other case, just gamble on having __inline__, and let the user + * define C11THREADS_INLINE if it breaks + */ +#else +#define C11THREADS_INLINE __inline__ +#endif +#endif /* !defined C11THREADS_INLINE */ + +#include + +#ifndef TIME_UTC +#define TIME_UTC 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*thrd_start_t)(void*); +typedef void (*tss_dtor_t)(void*); + +enum { + mtx_plain = 0, + mtx_recursive = 1, + mtx_timed = 2, +}; + +enum { + thrd_success, + thrd_timedout, + thrd_busy, + thrd_error, + thrd_nomem +}; + +#ifndef C11THREADS_WIN32 +/* C11 threads over POSIX threads as thin static inline wrapper functions */ +#include +#include +#include +#include /* for sched_yield */ +#include + +#ifndef thread_local +#define thread_local _Thread_local +#endif + +#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT +#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS + +#ifdef __APPLE__ +/* Darwin doesn't implement timed mutexes currently */ +#define C11THREADS_NO_TIMED_MUTEX +#include +#ifndef __MAC_10_15 +#define C11THREADS_NO_TIMESPEC_GET +#endif +#elif __STDC_VERSION__ < 201112L +#define C11THREADS_NO_TIMESPEC_GET +#endif + +#ifdef C11THREADS_NO_TIMED_MUTEX +#define C11THREADS_TIMEDLOCK_POLL_INTERVAL 5000000 /* 5 ms */ +#endif + +/* types */ +typedef pthread_t thrd_t; +typedef pthread_mutex_t mtx_t; +typedef pthread_cond_t cnd_t; +typedef pthread_key_t tss_t; +typedef pthread_once_t once_flag; + +/* ---- thread management ---- */ + +static C11THREADS_INLINE int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + int res = pthread_create(thr, 0, (void*(*)(void*))func, arg); + if(res == 0) { + return thrd_success; + } + return res == ENOMEM ? thrd_nomem : thrd_error; +} + +static C11THREADS_INLINE void thrd_exit(int res) +{ + pthread_exit((void*)(intptr_t)res); +} + +static C11THREADS_INLINE int thrd_join(thrd_t thr, int *res) +{ + void *retval; + + if(pthread_join(thr, &retval) != 0) { + return thrd_error; + } + if(res) { + *res = (int)(intptr_t)retval; + } + return thrd_success; +} + +static C11THREADS_INLINE int thrd_detach(thrd_t thr) +{ + return pthread_detach(thr) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE thrd_t thrd_current(void) +{ + return pthread_self(); +} + +static C11THREADS_INLINE int thrd_equal(thrd_t a, thrd_t b) +{ + return pthread_equal(a, b); +} + +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out) +{ + if(nanosleep(ts_in, rem_out) < 0) { + if(errno == EINTR) return -1; + return -2; + } + return 0; +} + +static C11THREADS_INLINE void thrd_yield(void) +{ + sched_yield(); +} + +/* ---- mutexes ---- */ + +static C11THREADS_INLINE int mtx_init(mtx_t *mtx, int type) +{ + int res; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + + if(type & mtx_timed) { +#ifdef PTHREAD_MUTEX_TIMED_NP + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP); +#else + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); +#endif + } + if(type & mtx_recursive) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + + res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error; + pthread_mutexattr_destroy(&attr); + return res; +} + +static C11THREADS_INLINE void mtx_destroy(mtx_t *mtx) +{ + pthread_mutex_destroy(mtx); +} + +static C11THREADS_INLINE int mtx_lock(mtx_t *mtx) +{ + int res = pthread_mutex_lock(mtx); + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_trylock(mtx_t *mtx) +{ + int res = pthread_mutex_trylock(mtx); + if(res == EBUSY) { + return thrd_busy; + } + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + int res = 0; +#ifdef C11THREADS_NO_TIMED_MUTEX + /* fake a timedlock by polling trylock in a loop and waiting for a bit */ + struct timeval now; + struct timespec sleeptime; + + sleeptime.tv_sec = 0; + sleeptime.tv_nsec = C11THREADS_TIMEDLOCK_POLL_INTERVAL; + + while((res = pthread_mutex_trylock(mtx)) == EBUSY) { + gettimeofday(&now, NULL); + + if(now.tv_sec > ts->tv_sec || (now.tv_sec == ts->tv_sec && + (now.tv_usec * 1000) >= ts->tv_nsec)) { + return thrd_timedout; + } + + nanosleep(&sleeptime, NULL); + } +#else + if((res = pthread_mutex_timedlock(mtx, ts)) == ETIMEDOUT) { + return thrd_timedout; + } +#endif + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_unlock(mtx_t *mtx) +{ + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; +} + +/* ---- condition variables ---- */ + +static C11THREADS_INLINE int cnd_init(cnd_t *cond) +{ + return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void cnd_destroy(cnd_t *cond) +{ + pthread_cond_destroy(cond); +} + +static C11THREADS_INLINE int cnd_signal(cnd_t *cond) +{ + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_broadcast(cnd_t *cond) +{ + return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ + int res; + + if((res = pthread_cond_timedwait(cond, mtx, ts)) != 0) { + return res == ETIMEDOUT ? thrd_timedout : thrd_error; + } + return thrd_success; +} + +/* ---- thread-specific data ---- */ + +static C11THREADS_INLINE int tss_create(tss_t *key, tss_dtor_t dtor) +{ + return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void tss_delete(tss_t key) +{ + pthread_key_delete(key); +} + +static C11THREADS_INLINE int tss_set(tss_t key, void *val) +{ + return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void *tss_get(tss_t key) +{ + return pthread_getspecific(key); +} + +/* ---- misc ---- */ + +static C11THREADS_INLINE void call_once(once_flag *flag, void (*func)(void)) +{ + pthread_once(flag, func); +} + +#ifdef C11THREADS_NO_TIMESPEC_GET +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base) +{ + struct timeval tv; + + if(base != TIME_UTC) { + return 0; + } + + if(gettimeofday(&tv, 0) == -1) { + return 0; + } + + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + return base; +} +#endif + + +#else /* C11THREADS_WIN32 */ + +/* C11 threads implementation using native Win32 API calls (see c11threads_win32.c) */ + +#ifndef thread_local +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#else +#define thread_local _Thread_local +#endif +#endif + +#define ONCE_FLAG_INIT {0} +#define TSS_DTOR_ITERATIONS 4 + +#ifndef _UCRT +#define C11THREADS_NO_TIMESPEC_GET +#endif + +#ifdef _MSC_VER +#define C11THREADS_MSVC_NORETURN __declspec(noreturn) +#define C11THREADS_GNUC_NORETURN +#elif defined(__GNUC__) +#define C11THREADS_MSVC_NORETURN +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5) +#define C11THREADS_GNUC_NORETURN __attribute__((noreturn)) +#else +#define C11THREADS_GNUC_NORETURN +#endif +#else +#define C11THREADS_MSVC_NORETURN +#define C11THREADS_GNUC_NORETURN +#endif + +/* types */ +typedef unsigned long thrd_t; +typedef struct { + void *debug_info; + long lock_count; + long recursion_count; + void *owning_thread; + void *lock_semaphore; + void *spin_count; +} mtx_t; +typedef void *cnd_t; +typedef unsigned long tss_t; +typedef void *once_flag; +struct _c11threads_win32_timespec32_t { + long tv_sec; + long tv_nsec; +}; +struct _c11threads_win32_timespec64_t { +#ifdef _MSC_VER + __int64 tv_sec; +#else + long long tv_sec; +#endif + long tv_nsec; +}; +#if !defined(_UCRT) && !defined(_TIMESPEC_DEFINED) +#ifdef _USE_32BIT_TIME_T +struct timespec { + long tv_sec; + long tv_nsec; +}; +#elif !defined(_USE_32BIT_TIME_T) +struct timespec { + __int64 tv_sec; + long tv_nsec; +}; +#endif /* !defined(_USE_32BIT_TIME_T) */ +#endif /* !defined(_UCRT) && !defined(_TIMESPEC_DEFINED) */ + +/* Thread functions. */ + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); +/* Win32: Threads not created with thrd_create() need to call this to clean up TSS. */ +C11THREADS_MSVC_NORETURN void thrd_exit(int res) C11THREADS_GNUC_NORETURN; +int thrd_join(thrd_t thr, int *res); +int thrd_detach(thrd_t thr); +thrd_t thrd_current(void); +int thrd_equal(thrd_t a, thrd_t b); +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out); +void thrd_yield(void); + +/* Mutex functions. */ + +int mtx_init(mtx_t *mtx, int type); +void mtx_destroy(mtx_t *mtx); +int mtx_lock(mtx_t *mtx); +int mtx_trylock(mtx_t *mtx); +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); +int mtx_unlock(mtx_t *mtx); + +/* Condition variable functions. */ + +int cnd_init(cnd_t *cond); +void cnd_destroy(cnd_t *cond); +int cnd_signal(cnd_t *cond); +int cnd_broadcast(cnd_t *cond); +int cnd_wait(cnd_t *cond, mtx_t *mtx); +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); + +/* Thread-specific storage functions. */ + +int tss_create(tss_t *key, tss_dtor_t dtor); +void tss_delete(tss_t key); +int tss_set(tss_t key, void *val); +void *tss_get(tss_t key); + +/* One-time callable function. */ + +void call_once(once_flag *flag, void (*func)(void)); + +#ifdef C11THREADS_NO_TIMESPEC_GET +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base); +#endif + +/* Special Win32 functions. */ +/* Win32: Free resources associated with this library. */ +void c11threads_win32_destroy(void); +/* Win32: Register current Win32 thread in c11threads to allow for proper thrd_join(). */ +int c11threads_win32_thrd_self_register(void); +/* Win32: Register Win32 thread by ID in c11threads to allow for proper thrd_join(). */ +int c11threads_win32_thrd_register(unsigned long win32_thread_id); + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) /* Warning C4127: conditional expression is constant */ +#endif + +/* ---- thread management ---- */ + +int _c11threads_win32_thrd_sleep32(const struct _c11threads_win32_timespec32_t *ts_in, struct _c11threads_win32_timespec32_t *rem_out); +int _c11threads_win32_thrd_sleep64(const struct _c11threads_win32_timespec64_t *ts_in, struct _c11threads_win32_timespec64_t *rem_out); +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out) +{ + if (sizeof(ts_in->tv_sec) == 4) { + return _c11threads_win32_thrd_sleep32((const struct _c11threads_win32_timespec32_t*)ts_in, (struct _c11threads_win32_timespec32_t*)rem_out); + } else { + return _c11threads_win32_thrd_sleep64((const struct _c11threads_win32_timespec64_t*)ts_in, (struct _c11threads_win32_timespec64_t*)rem_out); + } +} + +/* ---- mutexes ---- */ + +int _c11threads_win32_mtx_timedlock32(mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts); +int _c11threads_win32_mtx_timedlock64(mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts); +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_mtx_timedlock32(mtx, (const struct _c11threads_win32_timespec32_t*)ts); + } else { + return _c11threads_win32_mtx_timedlock64(mtx, (const struct _c11threads_win32_timespec64_t*)ts); + } +} + +/* ---- condition variables ---- */ + +int _c11threads_win32_cnd_timedwait32(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts); +int _c11threads_win32_cnd_timedwait64(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts); +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_cnd_timedwait32(cond, mtx, (const struct _c11threads_win32_timespec32_t*)ts); + } else { + return _c11threads_win32_cnd_timedwait64(cond, mtx, (const struct _c11threads_win32_timespec64_t*)ts); + } +} + +/* ---- misc ---- */ + +#ifdef C11THREADS_NO_TIMESPEC_GET +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base); +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base); +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_timespec32_get((struct _c11threads_win32_timespec32_t*)ts, base); + } else { + return _c11threads_win32_timespec64_get((struct _c11threads_win32_timespec64_t*)ts, base); + } +} +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif /* C11THREADS_WIN32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* C11THREADS_H_ */ diff --git a/demo/caen-felib-demo-dpp-pha/c11threads_win32.c b/demo/caen-felib-demo-dpp-pha/c11threads_win32.c new file mode 100644 index 0000000..f8badec --- /dev/null +++ b/demo/caen-felib-demo-dpp-pha/c11threads_win32.c @@ -0,0 +1,1147 @@ +/* +Win32 implementation for c11threads. + +Authors: +John Tsiombikas +Oliver Old + +I place this piece of code in the public domain. Feel free to use as you see +fit. I'd appreciate it if you keep my name at the top of the code somewhere, but +whatever. + +Main project site: https://github.com/jtsiomb/c11threads +*/ + +#if defined(_WIN32) && !defined(C11THREADS_PTHREAD_WIN32) + +#ifdef _MSC_VER +/* Map debug malloc and free functions for debug builds. DO NOT CHANGE THE INCLUDE ORDER! */ +#define _CRTDBG_MAP_ALLOC +#include +#include +#endif + +#include "c11threads.h" + +#include +#include +#include + +#ifndef WINVER +#define WINVER 0x0400 /* Windows NT 4.0 */ +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT WINVER +#endif +#define WIN32_LEAN_AND_MEAN +#include + +#define _WIN32_WINNT_VISTA 0x0600 +#define THREAD_QUERY_LIMITED_INFORMATION (0x0800) + + +/* ---- library ---- */ + +typedef void (__stdcall *_c11threads_win32_InitializeConditionVariable_t)(void*); +typedef void (__stdcall *_c11threads_win32_WakeConditionVariable_t)(void*); +typedef void (__stdcall *_c11threads_win32_WakeAllConditionVariable_t)(void*); +typedef int (__stdcall *_c11threads_win32_SleepConditionVariableCS_t)(void*, PCRITICAL_SECTION, unsigned long); +typedef int (__stdcall *_c11threads_win32_InitOnceExecuteOnce_t)(void*, const void*, void*, void**); + +struct _c11threads_win32_thrd_entry_t { + struct _c11threads_win32_thrd_entry_t *next; + void *h; + thrd_t thrd; +}; + +struct _c11threads_win32_tss_dtor_entry_t { + struct _c11threads_win32_tss_dtor_entry_t *next; + tss_dtor_t dtor; + tss_t key; +}; + +static volatile long _c11threads_win32_initialized = 0; +static unsigned short _c11threads_win32_winver; +static _c11threads_win32_InitializeConditionVariable_t _c11threads_win32_InitializeConditionVariable; +static _c11threads_win32_WakeConditionVariable_t _c11threads_win32_WakeConditionVariable; +static _c11threads_win32_WakeAllConditionVariable_t _c11threads_win32_WakeAllConditionVariable; +static _c11threads_win32_SleepConditionVariableCS_t _c11threads_win32_SleepConditionVariableCS; +static _c11threads_win32_InitOnceExecuteOnce_t _c11threads_win32_InitOnceExecuteOnce; +static CRITICAL_SECTION _c11threads_win32_thrd_list_critical_section; +static struct _c11threads_win32_thrd_entry_t *_c11threads_win32_thrd_list_head = NULL; +static CRITICAL_SECTION _c11threads_win32_tss_dtor_list_critical_section; +static struct _c11threads_win32_tss_dtor_entry_t *_c11threads_win32_tss_dtor_list_head = NULL; + +#ifdef _MSC_VER +#pragma warning(push) +/* Warning C4996: 'GetVersion': was declared deprecated */ +/* Warning C28125: The function 'InitializeCriticalSection' must be called from within a try/except block. */ +/* Warning C28159: Consider using 'IsWindows*' instead of 'GetVersion'. Reason: Deprecated. Use VerifyVersionInfo* or IsWindows* macros from VersionHelpers. */ +#pragma warning(disable: 4996 28125 28159) +#endif +static void _c11threads_win32_init(void) +{ + unsigned short os_version; + os_version = (unsigned short)GetVersion(); /* Keep in mind: Maximum version for unmanifested apps is Windows 8 (0x0602). */ + _c11threads_win32_winver = (os_version << 8) | (os_version >> 8); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + void *kernel32; + kernel32 = GetModuleHandleW(L"kernel32.dll"); + if (!kernel32) { + abort(); + } + _c11threads_win32_InitializeConditionVariable = (_c11threads_win32_InitializeConditionVariable_t)GetProcAddress(kernel32, "InitializeConditionVariable"); + if (!_c11threads_win32_InitializeConditionVariable) { + abort(); + } + _c11threads_win32_WakeConditionVariable = (_c11threads_win32_WakeConditionVariable_t)GetProcAddress(kernel32, "WakeConditionVariable"); + if (!_c11threads_win32_WakeConditionVariable) { + abort(); + } + _c11threads_win32_WakeAllConditionVariable = (_c11threads_win32_WakeAllConditionVariable_t)GetProcAddress(kernel32, "WakeAllConditionVariable"); + if (!_c11threads_win32_WakeAllConditionVariable) { + abort(); + } + _c11threads_win32_SleepConditionVariableCS = (_c11threads_win32_SleepConditionVariableCS_t)GetProcAddress(kernel32, "SleepConditionVariableCS"); + if (!_c11threads_win32_SleepConditionVariableCS) { + abort(); + } + _c11threads_win32_InitOnceExecuteOnce = (_c11threads_win32_InitOnceExecuteOnce_t)GetProcAddress(kernel32, "InitOnceExecuteOnce"); + if (!_c11threads_win32_InitOnceExecuteOnce) { + abort(); + } + } + InitializeCriticalSection(&_c11threads_win32_thrd_list_critical_section); + InitializeCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static void _c11threads_win32_ensure_initialized(void) +{ + if (InterlockedCompareExchange(&_c11threads_win32_initialized, 1, 0) == 0) { + _c11threads_win32_init(); + InterlockedExchange(&_c11threads_win32_initialized, 2); + } else { +#ifdef _MSC_VER +#pragma warning(suppress: 28112) /* Warning C28112: A variable (_c11threads_win32_initialized) which is accessed via an Interlocked function must always be accessed via an Interlocked function. */ +#endif + while (_c11threads_win32_initialized == 1) { + Sleep(0); + } + } +} + +void c11threads_win32_destroy(void) +{ + struct _c11threads_win32_thrd_entry_t *thrd_entry; + struct _c11threads_win32_thrd_entry_t *thrd_entry_temp; + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry; + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry_temp; + + if (_c11threads_win32_initialized) { + DeleteCriticalSection(&_c11threads_win32_thrd_list_critical_section); + DeleteCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + thrd_entry = _c11threads_win32_thrd_list_head; + while (thrd_entry) { + thrd_entry_temp = thrd_entry->next; + CloseHandle(thrd_entry->h); + free(thrd_entry); + thrd_entry = thrd_entry_temp; + } + + tss_dtor_entry = _c11threads_win32_tss_dtor_list_head; + while (tss_dtor_entry) { + tss_dtor_entry_temp = tss_dtor_entry->next; + TlsFree(tss_dtor_entry->key); + free(tss_dtor_entry); + tss_dtor_entry = tss_dtor_entry_temp; + } + + _c11threads_win32_initialized = 0; + _c11threads_win32_thrd_list_head = NULL; + _c11threads_win32_tss_dtor_list_head = NULL; + } +} + +/* ---- utilities ---- */ + +static int _c11threads_win32_util_is_timespec32_valid(const struct _c11threads_win32_timespec32_t *ts) +{ + return ts->tv_sec >= 0 && ts->tv_nsec >= 0 && ts->tv_nsec <= 999999999; +} + +static int _c11threads_win32_util_is_timespec64_valid(const struct _c11threads_win32_timespec64_t *ts) +{ + return ts->tv_sec >= 0 && ts->tv_nsec >= 0 && ts->tv_nsec <= 999999999; +} + +/* Precondition: 'ts' validated. */ +static __int64 _c11threads_win32_util_timespec32_to_file_time(const struct _c11threads_win32_timespec32_t *ts) +{ + unsigned __int64 sec_res; + unsigned __int64 nsec_res; + + sec_res = (unsigned __int64)ts->tv_sec * (unsigned __int64)10000000; + + /* Add another 100 ns if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 100UL + !!((unsigned long)ts->tv_nsec % 100UL); + + return sec_res + nsec_res; +} + +/* Precondition: 'ts' validated. */ +static __int64 _c11threads_win32_util_timespec64_to_file_time(const struct _c11threads_win32_timespec64_t *ts, size_t *periods) +{ + unsigned __int64 sec_res; + unsigned __int64 nsec_res; + unsigned __int64 res; + + *periods = (unsigned long)((unsigned __int64)ts->tv_sec / (unsigned __int64)922337203685); + sec_res = ((unsigned __int64)ts->tv_sec % (unsigned __int64)922337203685) * (unsigned __int64)10000000; + + /* Add another 100 ns if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 100UL + !!((unsigned long)ts->tv_nsec % 100UL); + + /* 64-bit time_t may cause overflow. */ + if (nsec_res > (unsigned __int64) - 1 - sec_res) { + ++*periods; + nsec_res -= (unsigned __int64) - 1 - sec_res; + sec_res = 0; + } + + res = sec_res + nsec_res; + + if (*periods && !res) { + --*periods; + return (__int64)9223372036850000000; + } + + return res; +} + +/* Precondition: 'ts' validated. */ +static int _c11threads_win32_util_timespec32_to_milliseconds(const struct _c11threads_win32_timespec32_t *ts, unsigned long *ms) +{ + unsigned long sec_res; + unsigned long nsec_res; + + /* Overflow. */ + if ((unsigned long)ts->tv_sec > (INFINITE - 1UL) / 1000UL) { + return 0; + } + + sec_res = (unsigned long)ts->tv_sec * 1000UL; + /* Add another millisecond if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 1000000UL + !!((unsigned long)ts->tv_nsec % 1000000UL); + + /* Overflow. */ + if (nsec_res > INFINITE - 1UL - sec_res) { + return 0; + } + + *ms = sec_res + nsec_res; + return 1; +} + +/* Precondition: 'ts' validated. */ +static int _c11threads_win32_util_timespec64_to_milliseconds(const struct _c11threads_win32_timespec64_t *ts, unsigned long *ms) +{ + unsigned long sec_res; + unsigned long nsec_res; + + /* Overflow. */ + if ((unsigned __int64)ts->tv_sec > (INFINITE - 1UL) / 1000UL) { + return 0; + } + + sec_res = (unsigned long)ts->tv_sec * 1000UL; + /* Add another millisecond if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 1000000UL + !!((unsigned long)ts->tv_nsec % 1000000UL); + + /* Overflow. */ + if (nsec_res > INFINITE - 1UL - sec_res) { + return 0; + } + + *ms = sec_res + nsec_res; + return 1; +} + +/* Precondition: 'current_time' and 'end_time' validated. */ +static unsigned long _c11threads_win32_util_timepoint_to_millisecond_timespan32(const struct _c11threads_win32_timespec32_t *current_time, const struct _c11threads_win32_timespec32_t *end_time, int *clamped) { + unsigned long wait_time; + struct _c11threads_win32_timespec32_t ts; + + *clamped = 0; + if (current_time->tv_sec > end_time->tv_sec || (current_time->tv_sec == end_time->tv_sec && current_time->tv_nsec >= end_time->tv_nsec)) { + wait_time = 0; + } else { + ts.tv_sec = end_time->tv_sec - current_time->tv_sec; + ts.tv_nsec = end_time->tv_nsec - current_time->tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000; + } + + if (!_c11threads_win32_util_timespec32_to_milliseconds(&ts, &wait_time)) { + /* Clamp wait_time. Pretend we've had a spurious wakeup if expired. */ + wait_time = INFINITE - 1; + *clamped = 1; + } + } + + return wait_time; +} + +/* Precondition: 'current_time' and 'end_time' validated. */ +static unsigned long _c11threads_win32_util_timepoint_to_millisecond_timespan64(const struct _c11threads_win32_timespec64_t *current_time, const struct _c11threads_win32_timespec64_t *end_time, int *clamped) { + unsigned long wait_time; + struct _c11threads_win32_timespec64_t ts; + + *clamped = 0; + if (current_time->tv_sec > end_time->tv_sec || (current_time->tv_sec == end_time->tv_sec && current_time->tv_nsec >= end_time->tv_nsec)) { + wait_time = 0; + } else { + ts.tv_sec = end_time->tv_sec - current_time->tv_sec; + ts.tv_nsec = end_time->tv_nsec - current_time->tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000; + } + + if (!_c11threads_win32_util_timespec64_to_milliseconds(&ts, &wait_time)) { + /* Clamp wait_time. Pretend we've had a spurious wakeup if expired. */ + wait_time = INFINITE - 1; + *clamped = 1; + } + } + + return wait_time; +} + +#if defined(C11THREADS_NO_TIMESPEC_GET) || !defined(_MSC_VER) +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base) +{ + FILETIME file_time; + ULARGE_INTEGER li; + + if (base != TIME_UTC) { + return 0; + } + + GetSystemTimeAsFileTime(&file_time); + + li.LowPart = file_time.dwLowDateTime; + li.HighPart = file_time.dwHighDateTime; + + /* Also subtract difference between FILETIME and UNIX time epoch. It's 369 years by the way. */ + ts->tv_sec = (long)(li.QuadPart / (unsigned __int64)10000000 - (unsigned __int64)11644473600); + ts->tv_nsec = (long)(li.QuadPart % (unsigned __int64)10000000) * 100; + + return base; +} + +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base) +{ + FILETIME file_time; + ULARGE_INTEGER li; + + if (base != TIME_UTC) { + return 0; + } + + GetSystemTimeAsFileTime(&file_time); + + li.LowPart = file_time.dwLowDateTime; + li.HighPart = file_time.dwHighDateTime; + + /* Also subtract difference between FILETIME and UNIX time epoch. It's 369 years by the way. */ + ts->tv_sec = li.QuadPart / (unsigned __int64)10000000 - (unsigned __int64)11644473600; + ts->tv_nsec = (long)(li.QuadPart % (unsigned __int64)10000000) * 100; + + return base; +} +#else +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base) +{ + return _timespec32_get((struct _timespec32*)ts, base); +} + +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base) +{ + return _timespec64_get((struct _timespec64*)ts, base); +} +#endif + +/* ---- thread management ---- */ + +static int _c11threads_win32_thrd_register(thrd_t thrd, HANDLE h) +{ + struct _c11threads_win32_thrd_entry_t *thread_entry; + + thread_entry = malloc(sizeof(*thread_entry)); + if (!thread_entry) { + return 0; + } + + thread_entry->thrd = thrd; + thread_entry->h = h; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + thread_entry->next = _c11threads_win32_thrd_list_head; + _c11threads_win32_thrd_list_head = thread_entry; + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + return 1; +} + +static void *_c11threads_win32_thrd_pop_entry(thrd_t thrd) +{ + void *h; + struct _c11threads_win32_thrd_entry_t *prev; + struct _c11threads_win32_thrd_entry_t *curr; + struct _c11threads_win32_thrd_entry_t *next; + + h = NULL; + prev = NULL; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + curr = _c11threads_win32_thrd_list_head; + while (curr) + { + if (curr->thrd == thrd) { + h = curr->h; + next = curr->next; + if (prev) { + prev->next = next; + } else { + _c11threads_win32_thrd_list_head = next; + } + break; + } + + prev = curr; + curr = curr->next; + } + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + free(curr); + return h; +} + +static void _c11threads_win32_thrd_run_tss_dtors(void) +{ + int ran_dtor; + size_t i; + struct _c11threads_win32_tss_dtor_entry_t *prev; + struct _c11threads_win32_tss_dtor_entry_t *curr; + struct _c11threads_win32_tss_dtor_entry_t *next; + void *val; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + ran_dtor = 1; + for (i = 0; i < TSS_DTOR_ITERATIONS && ran_dtor; ++i) { + ran_dtor = 0; + prev = NULL; + curr = _c11threads_win32_tss_dtor_list_head; + + while (curr) { + val = TlsGetValue(curr->key); + if (val) { + TlsSetValue(curr->key, NULL); + curr->dtor(val); + ran_dtor = 1; + } else if (GetLastError() != ERROR_SUCCESS) { + next = curr->next; + free(curr); + if (prev) { + prev->next = next; + } else { + _c11threads_win32_tss_dtor_list_head = next; + } + curr = next; + continue; + } + + curr = curr->next; + } + } + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); +} + +int c11threads_win32_thrd_self_register(void) +{ + unsigned long desired_access; + void *process; + void *thread; + + desired_access = SYNCHRONIZE | THREAD_QUERY_INFORMATION; + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + desired_access = SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION; + } + + process = GetCurrentProcess(); + thread = GetCurrentThread(); + if (!DuplicateHandle(process, thread, process, &thread, desired_access, 0, 0)) { + return thrd_error; + } + if (!_c11threads_win32_thrd_register(GetCurrentThreadId(), thread)) { + CloseHandle(thread); + return thrd_nomem; + } + return thrd_success; +} + +int c11threads_win32_thrd_register(unsigned long win32_thread_id) +{ + /* XXX temporary hack to make this build on MSVC6. Investigate further */ +#ifdef _PROCESSTHREADSAPI_H_ + unsigned long desired_access; + void *h; + + desired_access = SYNCHRONIZE | THREAD_QUERY_INFORMATION; + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + desired_access = SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION; + } + + h = OpenThread(desired_access, 0, win32_thread_id); + if (!h) { + return thrd_error; + } + if (!_c11threads_win32_thrd_register(win32_thread_id, h)) { + CloseHandle(h); + return thrd_nomem; + } +#endif + return thrd_success; +} + +struct _c11threads_win32_thrd_start_thunk_parameters_t { + thrd_start_t func; + void *arg; +}; + +static int __stdcall _c11threads_win32_thrd_start_thunk(struct _c11threads_win32_thrd_start_thunk_parameters_t *start_parameters) +{ + int res; + struct _c11threads_win32_thrd_start_thunk_parameters_t local_start_params; + local_start_params = *start_parameters; + free(start_parameters); + res = local_start_params.func(local_start_params.arg); + _c11threads_win32_thrd_run_tss_dtors(); + return res; +} + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + struct _c11threads_win32_thrd_start_thunk_parameters_t *thread_start_params; + struct _c11threads_win32_thrd_entry_t *thread_entry; + void *h; + + thread_start_params = malloc(sizeof(*thread_start_params)); + if (!thread_start_params) { + return thrd_nomem; + } + + thread_start_params->func = func; + thread_start_params->arg = arg; + + thread_entry = malloc(sizeof(*thread_entry)); + if (!thread_entry) { + free(thread_start_params); + return thrd_nomem; + } + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + h = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)_c11threads_win32_thrd_start_thunk, thread_start_params, 0, thr); + if (!h) { + unsigned long error; + error = GetLastError(); + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + free(thread_start_params); + free(thread_entry); + return error == ERROR_NOT_ENOUGH_MEMORY ? thrd_nomem : thrd_error; + } + thread_entry->next = _c11threads_win32_thrd_list_head; + thread_entry->h = h; + thread_entry->thrd = *thr; + _c11threads_win32_thrd_list_head = thread_entry; + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + return thrd_success; +} + +void thrd_exit(int res) +{ + _c11threads_win32_thrd_run_tss_dtors(); + ExitThread(res); +} + +int thrd_join(thrd_t thr, int *res) +{ + int ret; + void *h; + + ret = thrd_error; + h = _c11threads_win32_thrd_pop_entry(thr); + if (h) { + if (WaitForSingleObject(h, INFINITE) == WAIT_OBJECT_0 && (!res || GetExitCodeThread(h, (unsigned long*)res))) { + ret = thrd_success; + } + + CloseHandle(h); + } + + return ret; +} + +int thrd_detach(thrd_t thr) +{ + void *h; + h = _c11threads_win32_thrd_pop_entry(thr); + return h && CloseHandle(h) ? thrd_success : thrd_error; +} + +thrd_t thrd_current(void) +{ + return GetCurrentThreadId(); +} + +static int _c11threads_win32_sleep_common(__int64 file_time_in) +{ + void *timer; + unsigned long error; + LARGE_INTEGER due_time; + + assert(file_time_in >= 0); + + timer = CreateWaitableTimerW(NULL, 1, NULL); + if (!timer) { + error = GetLastError(); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + due_time.QuadPart = -file_time_in; + if (!SetWaitableTimer(timer, &due_time, 0, NULL, NULL, 0)) { + error = GetLastError(); + CloseHandle(timer); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) { + error = GetLastError(); + CloseHandle(timer); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + CloseHandle(timer); + return 0; /* Success. */ +} + +int _c11threads_win32_thrd_sleep32(const struct _c11threads_win32_timespec32_t *ts_in, struct _c11threads_win32_timespec32_t *rem_out) +{ + __int64 file_time; + int res; + + (void)rem_out; + + if (!_c11threads_win32_util_is_timespec32_valid(ts_in)) { + return -ERROR_INVALID_PARAMETER; + } + + file_time = _c11threads_win32_util_timespec32_to_file_time(ts_in); + if (file_time < 0) { + return -ERROR_INVALID_PARAMETER; + } + + res = _c11threads_win32_sleep_common(file_time); + + return res; +} + +int _c11threads_win32_thrd_sleep64(const struct _c11threads_win32_timespec64_t *ts_in, struct _c11threads_win32_timespec64_t *rem_out) +{ + __int64 file_time; + size_t periods; + int res; + + (void)rem_out; + + if (!_c11threads_win32_util_is_timespec64_valid(ts_in)) { + return -ERROR_INVALID_PARAMETER; + } + + file_time = _c11threads_win32_util_timespec64_to_file_time(ts_in, &periods); + if (file_time < 0) { + return -ERROR_INVALID_PARAMETER; + } + +restart_sleep: + res = _c11threads_win32_sleep_common(file_time); + + if (!res && periods) { + --periods; + file_time = (__int64)9223372036850000000; + goto restart_sleep; + } + + return res; +} + +void thrd_yield(void) +{ + SwitchToThread(); +} + +/* ---- mutexes ---- */ + +int mtx_init(mtx_t *mtx, int type) +{ + (void)type; +#ifdef _MSC_VER +#pragma warning(suppress: 28125) /* Warning C28125: The function 'InitializeCriticalSection' must be called from within a try/except block. */ +#endif + InitializeCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +void mtx_destroy(mtx_t *mtx) +{ + DeleteCriticalSection((PCRITICAL_SECTION)mtx); +} + +int mtx_lock(mtx_t *mtx) +{ + EnterCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +int mtx_trylock(mtx_t *mtx) +{ + return TryEnterCriticalSection((PCRITICAL_SECTION)mtx) ? thrd_success : thrd_busy; +} + +int _c11threads_win32_mtx_timedlock32(mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts) +{ + int success; + struct _c11threads_win32_timespec32_t ts_current; + + if (!_c11threads_win32_util_is_timespec32_valid(ts)) { + return thrd_error; + } + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + while (!success) { + if (!_c11threads_win32_timespec32_get(&ts_current, TIME_UTC)) { + return thrd_error; + } + + if (ts_current.tv_sec > ts->tv_sec || (ts_current.tv_sec == ts->tv_sec && ts_current.tv_nsec >= ts->tv_nsec)) { + return thrd_timedout; + } + + Sleep(0); + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + } + + return thrd_success; +} + +int _c11threads_win32_mtx_timedlock64(mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts) +{ + int success; + struct _c11threads_win32_timespec64_t ts_current; + + if (!_c11threads_win32_util_is_timespec64_valid(ts)) { + return thrd_error; + } + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + while (!success) { + if (!_c11threads_win32_timespec64_get(&ts_current, TIME_UTC)) { + return thrd_error; + } + + if (ts_current.tv_sec > ts->tv_sec || (ts_current.tv_sec == ts->tv_sec && ts_current.tv_nsec >= ts->tv_nsec)) { + return thrd_timedout; + } + + Sleep(0); + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + } + + return thrd_success; +} + +int mtx_unlock(mtx_t *mtx) +{ + LeaveCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +/* ---- condition variables ---- */ + +struct _c11threads_win32_cnd_t { + void *mutex; + void *signal_sema; + void *broadcast_event; + size_t wait_count; +}; + +int cnd_init(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_InitializeConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + + cnd = malloc(sizeof(*cnd)); + if (!cnd) { + return thrd_nomem; + } + + cnd->mutex = CreateMutexW(NULL, 0, NULL); + if (cnd->mutex) { + cnd->signal_sema = CreateSemaphoreW(NULL, 0, 0x7fffffff, NULL); + if (cnd->signal_sema) { + cnd->broadcast_event = CreateEventW(NULL, 1, 0, NULL); + if (cnd->broadcast_event) { + cnd->wait_count = 0; + *cond = cnd; + return thrd_success; + } + CloseHandle(cnd->signal_sema); + } + CloseHandle(cnd->mutex); + } + + free(cnd); + return thrd_error; + } +} + +void cnd_destroy(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver < _WIN32_WINNT_VISTA) { + struct _c11threads_win32_cnd_t *cnd; + cnd = *cond; + assert(!cnd->wait_count); + CloseHandle(cnd->mutex); + CloseHandle(cnd->signal_sema); + CloseHandle(cnd->broadcast_event); + free(cnd); + } +} + +int cnd_signal(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_WakeConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + int success; + unsigned long wait_status; + + cnd = *cond; + + success = 0; + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_OBJECT_0) { + success = 1; + } else if (wait_status == WAIT_ABANDONED) { + abort(); + } + + if (success) { + if (cnd->wait_count) { + success = ReleaseSemaphore(cnd->signal_sema, 1, NULL) || GetLastError() == ERROR_TOO_MANY_POSTS; + } + if (!ReleaseMutex(cnd->mutex)) { + success = 0; + } + } + + return success ? thrd_success : thrd_error; + } +} + +int cnd_broadcast(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_WakeAllConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + int success; + unsigned long wait_status; + + cnd = *cond; + + success = 0; + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_OBJECT_0) { + success = 1; + } else if (wait_status == WAIT_ABANDONED) { + abort(); + } + + if (success) { + if (cnd->wait_count) { + success = SetEvent(cnd->broadcast_event); + } + if (!ReleaseMutex(cnd->mutex)) { + success = 0; + } + } + + return success ? thrd_success : thrd_error; + } +} + +static int _c11threads_win32_cnd_wait_common(cnd_t *cond, mtx_t *mtx, unsigned long wait_time, int clamped) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + if (_c11threads_win32_SleepConditionVariableCS(cond, (PCRITICAL_SECTION)mtx, wait_time)) { + return thrd_success; + } + + if (GetLastError() == ERROR_TIMEOUT) { + return clamped ? thrd_success : thrd_timedout; + } + + return thrd_error; + } else { + struct _c11threads_win32_cnd_t *cnd; + unsigned long wait_status; + unsigned long wait_status_2; + int res; + + cnd = *cond; + + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_ABANDONED) { + abort(); + } else if (wait_status != WAIT_OBJECT_0) { + return thrd_error; + } + LeaveCriticalSection((PCRITICAL_SECTION)mtx); + ++cnd->wait_count; + if (!ReleaseMutex(cnd->mutex)) { + abort(); + } + + wait_status = WaitForMultipleObjects(2, &cnd->signal_sema /* and cnd->broadcast_event */, 0, wait_time); + + if (WaitForSingleObject(cnd->mutex, INFINITE) != WAIT_OBJECT_0) { + abort(); + } + --cnd->wait_count; + if (!cnd->wait_count) { + do { + wait_status_2 = WaitForSingleObject(cnd->signal_sema, 0); + } while (wait_status_2 == WAIT_OBJECT_0); + if (wait_status_2 != WAIT_TIMEOUT) { + abort(); + } + + if (!ResetEvent(cnd->broadcast_event)) { + abort(); + } + } + if (!ReleaseMutex(cnd->mutex)) { + abort(); + } + + res = thrd_success; + if (wait_status == WAIT_TIMEOUT) { + if (!clamped) { + res = thrd_timedout; + } + } else if (wait_status != WAIT_OBJECT_0 && wait_status != WAIT_OBJECT_0 + 1) { + res = thrd_error; + } + + EnterCriticalSection((PCRITICAL_SECTION)mtx); + return res; + } +} + +int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return _c11threads_win32_cnd_wait_common(cond, mtx, INFINITE, 0); +} + +int _c11threads_win32_cnd_timedwait32(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts) +{ + struct _c11threads_win32_timespec32_t current_time; + unsigned long wait_time; + int clamped; + + if (!_c11threads_win32_util_is_timespec32_valid(ts)) { + return thrd_error; + } + + if (!_c11threads_win32_timespec32_get(¤t_time, TIME_UTC)) { + return thrd_error; + } + + wait_time = _c11threads_win32_util_timepoint_to_millisecond_timespan32(¤t_time, ts, &clamped); + + return _c11threads_win32_cnd_wait_common(cond, mtx, wait_time, clamped); +} + +int _c11threads_win32_cnd_timedwait64(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts) +{ + struct _c11threads_win32_timespec64_t current_time; + unsigned long wait_time; + int clamped; + + if (!_c11threads_win32_util_is_timespec64_valid(ts)) { + return thrd_error; + } + + if (!_c11threads_win32_timespec64_get(¤t_time, TIME_UTC)) { + return thrd_error; + } + + wait_time = _c11threads_win32_util_timepoint_to_millisecond_timespan64(¤t_time, ts, &clamped); + + return _c11threads_win32_cnd_wait_common(cond, mtx, wait_time, clamped); +} + +/* ---- thread-specific data ---- */ + +static int _c11threads_win32_tss_register(tss_t key, tss_dtor_t dtor) { + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry; + + tss_dtor_entry = malloc(sizeof(*tss_dtor_entry)); + if (!tss_dtor_entry) { + return 0; + } + + tss_dtor_entry->key = key; + tss_dtor_entry->dtor = dtor; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + tss_dtor_entry->next = _c11threads_win32_tss_dtor_list_head; + _c11threads_win32_tss_dtor_list_head = tss_dtor_entry; + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + return 1; +} + +static void _c11threads_win32_tss_deregister(tss_t key) { + struct _c11threads_win32_tss_dtor_entry_t *prev; + struct _c11threads_win32_tss_dtor_entry_t *curr; + struct _c11threads_win32_tss_dtor_entry_t *next; + + prev = NULL; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + curr = _c11threads_win32_tss_dtor_list_head; + while (curr) + { + if (curr->key == key) { + next = curr->next; + if (prev) { + prev->next = next; + } else { + _c11threads_win32_tss_dtor_list_head = next; + } + break; + } + + prev = curr; + curr = curr->next; + } + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + free(curr); +} + +int tss_create(tss_t *key, tss_dtor_t dtor) +{ + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) { + return thrd_error; + } + if (dtor && !_c11threads_win32_tss_register(*key, dtor)) { + TlsFree(*key); + return thrd_error; + } + return thrd_success; +} + +void tss_delete(tss_t key) +{ + _c11threads_win32_tss_deregister(key); + TlsFree(key); +} + +int tss_set(tss_t key, void *val) +{ + return TlsSetValue(key, val) ? thrd_success : thrd_error; +} + +void *tss_get(tss_t key) +{ + return TlsGetValue(key); +} + +/* ---- misc ---- */ + +static int __stdcall _c11threads_win32_call_once_thunk(void *init_once, void (*func)(void), void **context) +{ + (void)init_once; + (void)context; + func(); + return 1; +} + +void call_once(once_flag *flag, void (*func)(void)) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { +#ifdef _MSC_VER +#pragma warning(push) +/* Warning C4054: 'type cast' : from function pointer 'int (__stdcall *)(void *,void (__cdecl *)(void),void **)' to data pointer 'const void *' */ +/* Warning C4054: 'type cast' : from function pointer 'void (__cdecl *)(void)' to data pointer 'void *' */ +#pragma warning(disable: 4054) +#endif + _c11threads_win32_InitOnceExecuteOnce((void*)flag, (const void*)_c11threads_win32_call_once_thunk, (void*)func, NULL); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } else { + if (InterlockedCompareExchange((long*)flag, 1, 0) == 0) { + func(); + InterlockedExchange((long*)flag, 2); + } else { + while (*(volatile long*)flag == 1) { + Sleep(0); + } + } + } +} + +#endif diff --git a/demo/caen-felib-demo-dpp-pha/caen-felib-demo-dpp-pha.vcxproj b/demo/caen-felib-demo-dpp-pha/caen-felib-demo-dpp-pha.vcxproj new file mode 100644 index 0000000..7dcd390 --- /dev/null +++ b/demo/caen-felib-demo-dpp-pha/caen-felib-demo-dpp-pha.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {AD18C920-F454-43E7-85D8-25F0540841D0} + caenfelibdemodpppha + 10.0.16299.0 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-dpp-pha/caen-felib-demo-dpp-pha.vcxproj.filters b/demo/caen-felib-demo-dpp-pha/caen-felib-demo-dpp-pha.vcxproj.filters new file mode 100644 index 0000000..ef7db9a --- /dev/null +++ b/demo/caen-felib-demo-dpp-pha/caen-felib-demo-dpp-pha.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-dpp-pha/main.c b/demo/caen-felib-demo-dpp-pha/main.c new file mode 100644 index 0000000..29e0368 --- /dev/null +++ b/demo/caen-felib-demo-dpp-pha/main.c @@ -0,0 +1,895 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +* SPDX-License-Identifier: MIT-0 +* +***************************************************************************//*! +* +* \file main.c +* \brief CAEN Open FPGA Digitzers DPP-PHA demo +* \author Giovanni Cerretani, Alberto Potenza +* +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +// windows or C11 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_THREADS__) +#include +#else +#include "c11threads.h" +#endif + +#include + +// Basic hardcoded configuration +#define COMMAND_TRIGGER 't' +#define COMMAND_STOP 'q' +#define COMMAND_INCR_CH '+' +#define COMMAND_DECR_CH '-' +#define COMMAND_PLOT_WAVE 'w' +#define MAX_NUMBER_OF_SAMPLES (4095 * 2) +#define MAX_NUMBER_OF_BINS (1U << 16) +#define EVT_FILE_NAME "EventInfo.txt" +#define EVT_FILE_ENABLED true +#define HISTO_FILE_NAME "Histogram_%zu.txt" +#define WAVE_FILE_NAME "Waveform.txt" +#define DATA_FORMAT " \ + [ \ + { \"name\" : \"CHANNEL\", \"type\" : \"U8\" }, \ + { \"name\" : \"TIMESTAMP\", \"type\" : \"U64\" }, \ + { \"name\" : \"FINE_TIMESTAMP\", \"type\" : \"U16\" }, \ + { \"name\" : \"ENERGY\", \"type\" : \"U16\" }, \ + { \"name\" : \"ANALOG_PROBE_1\", \"type\" : \"I32\", \"dim\" : 1 }, \ + { \"name\" : \"ANALOG_PROBE_2\", \"type\" : \"I32\", \"dim\" : 1 }, \ + { \"name\" : \"DIGITAL_PROBE_1\", \"type\" : \"U8\", \"dim\" : 1 }, \ + { \"name\" : \"DIGITAL_PROBE_2\", \"type\" : \"U8\", \"dim\" : 1 }, \ + { \"name\" : \"DIGITAL_PROBE_3\", \"type\" : \"U8\", \"dim\" : 1 }, \ + { \"name\" : \"DIGITAL_PROBE_4\", \"type\" : \"U8\", \"dim\" : 1 }, \ + { \"name\" : \"ANALOG_PROBE_1_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"ANALOG_PROBE_2_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"DIGITAL_PROBE_1_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"DIGITAL_PROBE_2_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"DIGITAL_PROBE_3_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"DIGITAL_PROBE_4_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"WAVEFORM_SIZE\", \"type\" : \"SIZE_T\" }, \ + { \"name\" : \"FLAGS_LOW_PRIORITY\", \"type\" : \"U16\"}, \ + { \"name\" : \"FLAGS_HIGH_PRIORITY\", \"type\" : \"U16\" }, \ + { \"name\" : \"EVENT_SIZE\", \"type\" : \"SIZE_T\" } \ + ] \ +" + +// Utilities +#define ARRAY_SIZE(X) (sizeof(X)/sizeof((X)[0])) + +#ifdef _WIN32 // Windows +#include +#define GNUPLOT "pgnuplot.exe" +#else // Linux +#include +#include +#define GNUPLOT "gnuplot" +#define _popen(command, type) popen(command, type) +#define _pclose(command) pclose(command) +// Linux replacement for non standard _getch +static int _getch() { + struct termios oldattr; + if (tcgetattr(STDIN_FILENO, &oldattr) == -1) perror(NULL); + struct termios newattr = oldattr; + newattr.c_lflag &= ~(ICANON | ECHO); + if (tcsetattr(STDIN_FILENO, TCSANOW, &newattr) == -1) perror(NULL); + const int ch = getchar(); + if (tcsetattr(STDIN_FILENO, TCSANOW, &oldattr) == -1) perror(NULL); + return ch; +} +#endif + +static unsigned long long value_to_ull(const char* value) { + char* value_end; + const unsigned long long ret = strtoull(value, &value_end, 0); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtoull error\n"); + return ret; +} + +static double value_to_d(const char* value) { + char* value_end; + const double ret = strtod(value, &value_end); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtod error\n"); + return ret; +} + +static int print_last_error(void) { + char msg[1024]; + int ec = CAEN_FELib_GetLastError(msg); + if (ec != CAEN_FELib_Success) { + fprintf(stderr, "%s failed\n", __func__); + return ec; + } + fprintf(stderr, "last error: %s\n", msg); + return ec; +} + +static int connect_to_digitizer(uint64_t* dev_handle, int argc, char* argv[]) { + const char* path; + char local_path[256]; + printf("device path: "); + if (argc == 2) { + path = argv[1]; + puts(path); + } else { + while (fgets(local_path, sizeof(local_path), stdin) == NULL); + local_path[strcspn(local_path, "\r\n")] = '\0'; // remove newline added by fgets + path = local_path; + } + return CAEN_FELib_Open(path, dev_handle); +} + +static int get_n_channels(uint64_t dev_handle, size_t* n_channels) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + *n_channels = (size_t)value_to_ull(value); + return ret; +} + +static int print_digitizer_details(uint64_t dev_handle) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/ModelName", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Model name:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/SerialNum", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Serial number:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_Nbit", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC bits:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Channels:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_SamplRate", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC rate:\t%f Msps\n", value_to_d(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/cupver", value); + if (ret != CAEN_FELib_Success) return ret; + printf("CUP version:\t%s\n", value); + return ret; +} + +static int configure_digitizer(uint64_t dev_handle, size_t n_channels) { + + int ret; + char par_name[256]; + + // Channel settings + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChEnable", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "true"); + if (ret != CAEN_FELib_Success) return ret; + + // Global trigger configuration + ret = CAEN_FELib_SetValue(dev_handle, "/par/GlobalTriggerSource", "SwTrg | TestPulse"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulsePeriod", "100000000"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulseWidth", "16"); + if (ret != CAEN_FELib_Success) return ret; + + // Wave configuration + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChRecordLengthS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "512"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveTriggerSource", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "GlobalTriggerSource"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveAnalogProbe0", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "ADCInput"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveAnalogProbe1", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "TimeFilter"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveDigitalProbe0", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "Trigger"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveDigitalProbe1", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "TimeFilterArmed"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveDigitalProbe2", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "EnergyFilterBaselineFreeze"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveDigitalProbe3", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "EnergyFilterPeakReady"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChPreTriggerS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "200"); + if (ret != CAEN_FELib_Success) return ret; + + // Event configuration + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EventTriggerSource", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "GlobalTriggerSource"); + if (ret != CAEN_FELib_Success) return ret; + + // Filter parameters + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/TimeFilterRiseTimeS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "10"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EnergyFilterRiseTimeS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "100"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EnergyFilterFlatTopS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "100"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/TriggerThr", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "3"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EnergyFilterPeakingPosition", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "80"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EnergyFilterPoleZeroS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "1000"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/TimeFilterRetriggerGuardS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "10"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EnergyFilterPileupGuardT", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "10"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EnergyFilterBaselineGuardS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "100"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/PulsePolarity", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "Positive"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EnergyFilterLFLimitation", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "Off"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EnergyFilterBaselineAvg", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "Medium"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EnergyFilterFineGain", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "1.0"); + if (ret != CAEN_FELib_Success) return ret; + + return ret; + +} + +static int configure_endpoint(uint64_t ep_handle) { + int ret; + // conigure endpoint + uint64_t ep_folder_handle; + ret = CAEN_FELib_GetParentHandle(ep_handle, NULL, &ep_folder_handle); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(ep_folder_handle, "/par/activeendpoint", "dpppha"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetReadDataFormat(ep_handle, DATA_FORMAT); + if (ret != CAEN_FELib_Success) return ret; + return ret; +} + +struct counters { + size_t total_size; + size_t n_events; + time_t t_begin; +}; + +struct event { + uint8_t channel; + uint64_t timestamp; + double timestamp_us; + uint16_t fine_timestamp; + uint16_t energy; + uint16_t flags_low_priority; + uint16_t flags_high_priority; + size_t event_size; + int32_t* analog_probes[2]; + uint8_t* digital_probes[4]; + uint8_t analog_probes_type[2]; + uint8_t digital_probes_type[4]; + size_t n_allocated_samples; + size_t n_samples; +}; + +struct histograms { + uint32_t** histogram; + size_t n_allocated_channels; + size_t n_allocated_bins; +}; + +struct acq_data { + uint64_t dev_handle; + mtx_t mtx; + cnd_t cnd; + bool ep_configured; + bool acq_started; + size_t n_channels; + size_t active_channel; + bool plot_next_wave; +}; + +struct plotters { + FILE* gnuplot_h; + FILE* gnuplot_w; +}; + +static void print_stats(double t, size_t n_events, double rate) { + printf("\x1b[1K\rTime (s): %.1f\tEvents: %zu\tReadout rate (MB/s): %f", t, n_events, rate); + fflush(stdout); +} + +static void plot_histogram(FILE* gnuplot, size_t channel, struct histograms* h) { + char filename[64]; + snprintf(filename, ARRAY_SIZE(filename), HISTO_FILE_NAME, channel); + FILE* f_histo = fopen(filename, "w"); + if (f_histo == NULL) { + fprintf(stderr, "fopen failed"); + thrd_exit(EXIT_FAILURE); + } + uint32_t* hc = h->histogram[channel]; + for (size_t i = 0; i < h->n_allocated_bins; ++i) + fprintf(f_histo, "%"PRIu32"\n", hc[i]); + fclose(f_histo); + fprintf(gnuplot, "set title 'Histogram (channel %zu)'\n", channel); + fprintf(gnuplot, "plot '%s' with step\n", filename); + fflush(gnuplot); +} + +static const char* digital_probe_type(uint8_t type) { + switch (type) { + case 0: return "trigger"; + case 1: return "time_filter_armed"; + case 2: return "re_trigger_guard"; + case 3: return "energy_filter_baseline_freeze"; + case 4: return "energy_filter_peaking"; + case 5: return "energy_filter_peak_ready"; + case 6: return "energy_filter_pile_up_guard"; + case 7: return "event_pile_up"; + case 8: return "adc_saturation"; + case 9: return "adc_saturation_protection"; + case 10: return "post_saturation_event"; + case 11: return "energy_filter_saturation"; + case 12: return "signal_inhibit"; + default: return "UNKNOWN"; + } +} + +static const char* analog_probe_type(uint8_t type) { + switch (type) { + case 0: return "adc_input"; + case 1: return "time_filter"; + case 2: return "energy_filter"; + case 3: return "energy_filter_baseline"; + case 4: return "energy_filter_minus_baseline"; + default: return "UNKNOWN"; + } +} + +static void plot_waveform(FILE* gnuplot, struct event* evt) { + FILE* f_wave = fopen(WAVE_FILE_NAME, "w"); + if (f_wave == NULL) { + fprintf(stderr, "fopen failed"); + thrd_exit(EXIT_FAILURE); + } + fprintf(f_wave, "'%s'\t'%s'\t'%s'\t'%s'\t'%s'\t'%s'\n", + analog_probe_type(evt->analog_probes_type[0]), + analog_probe_type(evt->analog_probes_type[1]), + digital_probe_type(evt->digital_probes_type[0]), + digital_probe_type(evt->digital_probes_type[1]), + digital_probe_type(evt->digital_probes_type[2]), + digital_probe_type(evt->digital_probes_type[3]) + ); + for (size_t i = 0; i < evt->n_samples; ++i) + fprintf(f_wave, "%"PRIi32"\t%"PRIi32"\t%"PRIu8"\t%"PRIu8"\t%"PRIu8"\t%"PRIu8"\n", + evt->analog_probes[0][i], + evt->analog_probes[1][i], + evt->digital_probes[0][i], + evt->digital_probes[1][i], + evt->digital_probes[2][i], + evt->digital_probes[3][i] + ); + fclose(f_wave); + fprintf(gnuplot, "set title 'Waveform (channel %"PRIu8", timestamp %.3f us)'\n", evt->channel, evt->timestamp_us); + fprintf(gnuplot, "plot '%s' using 1 with step", WAVE_FILE_NAME); + fprintf(gnuplot, ", '' using 2 with step"); + fprintf(gnuplot, ", '' using (1000*$3 - 1100) with step"); + fprintf(gnuplot, ", '' using (1000*$4 - 2200) with step"); + fprintf(gnuplot, ", '' using (1000*$5 - 3300) with step"); + fprintf(gnuplot, ", '' using (1000*$6 - 4400) with step\n"); + fflush(gnuplot); +} + +static void save_event(FILE* f_evt, struct event* evt) { + const bool save_event = f_evt != NULL; + if (save_event) + fprintf(f_evt, "%"PRIu8"\t%.3f\t%"PRIu32"\n", evt->channel, evt->timestamp_us, evt->energy); +} + +static void fill_histogram(struct event* evt, struct histograms* h) { + /* + * fill histogram + * flags_high_priority bits: + * 0 or 1: pileup + * 2 or 3: adc saturation + * 4: energy ovverrange + */ + + // save events without these flags + if ((evt->flags_high_priority & 0x1f) == 0) + ++h->histogram[evt->channel][evt->energy]; + + // if trapsat is set, fill histogram last bin + else if (evt->flags_high_priority & 0x10) + ++h->histogram[evt->channel][h->n_allocated_bins - 1]; +} + +static double counters_dt(struct counters* c, time_t t) { + return difftime(t, c->t_begin); +} + +static double counters_rate(struct counters* c, time_t t) { + return c->total_size / counters_dt(c, t) / (1024. * 1024.); // MB/s +} + +static void counters_increment(struct counters* c, size_t size) { + c->total_size += size; + ++c->n_events; +} + +static void counters_reset(struct counters* c, time_t t) { + c->total_size = 0; + c->n_events = 0; + c->t_begin = t; +} + +static void read_data_loop(struct plotters* plotters, FILE* f_evt, struct acq_data* acq_data, uint64_t ep_handle, struct event* evt, struct histograms* h) { + + struct counters total; + struct counters interval; + + counters_reset(&total, time(NULL)); + counters_reset(&interval, total.t_begin); + + for (;;) { + const time_t current_time = time(NULL); + if (counters_dt(&interval, current_time) >= 1.) { + // print stats + print_stats(counters_dt(&total, current_time), total.n_events, counters_rate(&interval, current_time)); + counters_reset(&interval, current_time); + // plot histograms + mtx_lock(&acq_data->mtx); + plot_histogram(plotters->gnuplot_h, acq_data->active_channel, h); + mtx_unlock(&acq_data->mtx); + } + + const int ret = CAEN_FELib_ReadData(ep_handle, 100, + &evt->channel, + &evt->timestamp, + &evt->fine_timestamp, + &evt->energy, + evt->analog_probes[0], + evt->analog_probes[1], + evt->digital_probes[0], + evt->digital_probes[1], + evt->digital_probes[2], + evt->digital_probes[3], + &evt->analog_probes_type[0], + &evt->analog_probes_type[1], + &evt->digital_probes_type[0], + &evt->digital_probes_type[1], + &evt->digital_probes_type[2], + &evt->digital_probes_type[3], + &evt->n_samples, + &evt->flags_low_priority, + &evt->flags_high_priority, + &evt->event_size + ); + switch (ret) { + case CAEN_FELib_Success: { + + evt->timestamp_us = evt->timestamp * .008; + + counters_increment(&total, evt->event_size); + counters_increment(&interval, evt->event_size); + + fill_histogram(evt, h); + save_event(f_evt, evt); + + const bool has_waveform = evt->n_samples > 0; + + if (has_waveform) { + mtx_lock(&acq_data->mtx); + if (acq_data->plot_next_wave) { + acq_data->plot_next_wave = false; + plot_waveform(plotters->gnuplot_w, evt); + } + mtx_unlock(&acq_data->mtx); + } + + break; + } + case CAEN_FELib_Timeout: + break; + case CAEN_FELib_Stop: + printf("\nStop received.\n"); + return; + default: + print_last_error(); + break; + } + } +} + +static struct event* allocate_event(size_t n_samples) { + struct event* evt = malloc(sizeof(*evt)); + if (evt == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->n_allocated_samples = n_samples; + evt->n_samples = 0; + for (size_t i = 0; i < ARRAY_SIZE(evt->analog_probes); ++i) { + evt->analog_probes[i] = malloc(evt->n_allocated_samples * sizeof(*evt->analog_probes[i])); + if (evt->analog_probes[i] == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + } + for (size_t i = 0; i < ARRAY_SIZE(evt->digital_probes); ++i) { + evt->digital_probes[i] = malloc(evt->n_allocated_samples * sizeof(*evt->digital_probes[i])); + if (evt->digital_probes[i] == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + } + return evt; +} + +static void free_event(struct event* evt) { + for (size_t i = 0; i < ARRAY_SIZE(evt->analog_probes); ++i) + free(evt->analog_probes[i]); + for (size_t i = 0; i < ARRAY_SIZE(evt->digital_probes); ++i) + free(evt->digital_probes[i]); + free(evt); +} + +static struct histograms* allocate_histograms(size_t n_channels) { + struct histograms* histograms = malloc(sizeof(*histograms)); + if (histograms == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + histograms->n_allocated_channels = n_channels; + histograms->n_allocated_bins = MAX_NUMBER_OF_BINS; + histograms->histogram = malloc(histograms->n_allocated_channels * sizeof(*histograms->histogram)); + if (histograms->histogram == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + for (size_t i = 0; i < histograms->n_allocated_channels; ++i) { + histograms->histogram[i] = calloc(histograms->n_allocated_bins, sizeof(*histograms->histogram[i])); + if (histograms->histogram[i] == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + } + return histograms; +} + +static void free_histograms(struct histograms* h) { + for (size_t i = 0; i < h->n_allocated_channels; ++i) + free(h->histogram[i]); + free(h->histogram); +} + +static struct plotters* open_plotters() { + struct plotters* plotters = malloc(sizeof(*plotters)); + if (plotters == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + plotters->gnuplot_h = _popen(GNUPLOT, "w"); + if (plotters->gnuplot_h == NULL) { + fprintf(stderr, "popen failed"); + thrd_exit(EXIT_FAILURE); + } + plotters->gnuplot_w = _popen(GNUPLOT, "w"); + if (plotters->gnuplot_w == NULL) { + fprintf(stderr, "popen failed"); + thrd_exit(EXIT_FAILURE); + } + fprintf(plotters->gnuplot_h, "set xlabel 'ADC channels'\n"); + fprintf(plotters->gnuplot_h, "set ylabel 'Counts'\n"); + fprintf(plotters->gnuplot_h, "set grid\nset mouse\n"); + fflush(plotters->gnuplot_h); + + fprintf(plotters->gnuplot_w, "set key autotitle columnheader\n"); + fprintf(plotters->gnuplot_w, "set xlabel 'Samples'\n"); + fprintf(plotters->gnuplot_w, "set ylabel 'ADC counts'\n"); + fprintf(plotters->gnuplot_w, "set grid\nset mouse\n"); + fflush(plotters->gnuplot_w); + + return plotters; +} + +static void close_plotters(struct plotters* plotters) { + _pclose(plotters->gnuplot_h); + _pclose(plotters->gnuplot_w); +} + +static int acq_thread(void* p) { + + int ret; + + struct acq_data* data = (struct acq_data*)p; + uint64_t ep_handle; + + ret = CAEN_FELib_GetHandle(data->dev_handle, "/endpoint/dpppha", &ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = configure_endpoint(ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // allocate stuff + struct event *evt = allocate_event(MAX_NUMBER_OF_SAMPLES); + struct histograms* h = allocate_histograms(data->n_channels); + struct plotters* plt = open_plotters(); + + FILE* f_evt = NULL; + + if (EVT_FILE_ENABLED) { + f_evt = fopen(EVT_FILE_NAME, "w"); + if (f_evt == NULL) { + fprintf(stderr, "fopen failed"); + return EXIT_FAILURE; + } + } + + // signal main thread + mtx_lock(&data->mtx); + data->ep_configured = true; + mtx_unlock(&data->mtx); + cnd_signal(&data->cnd); + + // wait main thread + mtx_lock(&data->mtx); + while (!data->acq_started) + cnd_wait(&data->cnd, &data->mtx); + mtx_unlock(&data->mtx); + + // acquisition loop + read_data_loop(plt, f_evt, data, ep_handle, evt, h); + + // quit + if (f_evt != NULL) + fclose(f_evt); + close_plotters(plt); + free_event(evt); + free_histograms(h); + + return EXIT_SUCCESS; +} + +int main(int argc, char* argv[]) { + + printf("##########################################\n"); + printf("\tCAEN firmware DPP-PHA demo\n"); + printf("##########################################\n"); + + if (argc > 2) { + fputs("invalid arguments", stderr); + return EXIT_FAILURE; + } + + int ret; + + // select device + uint64_t dev_handle; + ret = connect_to_digitizer(&dev_handle, argc, argv); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = print_digitizer_details(dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + size_t n_channels; + ret = get_n_channels(dev_handle, &n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("Resetting...\t"); + + // reset + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/reset"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // start acquisition thread + struct acq_data data = { + .dev_handle = dev_handle, + .ep_configured = false, + .acq_started = false, + .n_channels = n_channels, + .active_channel = 0, + .plot_next_wave = false, + }; + mtx_init(&data.mtx, mtx_plain); + cnd_init(&data.cnd); + thrd_t thrd; + ret = thrd_create(&thrd, &acq_thread, &data); + if (ret != thrd_success) { + fprintf(stderr, "thrd_create failed"); + return EXIT_FAILURE; + } + + printf("Configuring...\t"); + + ret = configure_digitizer(dev_handle, n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // wait configuration on acquisition thread + mtx_lock(&data.mtx); + while (!data.ep_configured) + cnd_wait(&data.cnd, &data.mtx); + mtx_unlock(&data.mtx); + + printf("done.\n"); + + printf("Starting...\t"); + + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/armacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/swstartacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // notify start to acquisition thread + mtx_lock(&data.mtx); + data.acq_started = true; + mtx_unlock(&data.mtx); + cnd_signal(&data.cnd); + + printf("##########################################\n"); + printf("Commands supported:\n"); + printf("\t[%c]\tsend manual trigger\n", COMMAND_TRIGGER); + printf("\t[%c]\tstop acquisition\n", COMMAND_STOP); + printf("\t[%c]\tincrement channel\n", COMMAND_INCR_CH); + printf("\t[%c]\tdecrement channel\n", COMMAND_DECR_CH); + printf("\t[%c]\tplot next waveform\n", COMMAND_PLOT_WAVE); + printf("##########################################\n"); + + bool do_quit = false; + + do { + const int c = _getch(); + switch (c) { + case COMMAND_TRIGGER: { + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/sendswtrigger"); + if (ret != CAEN_FELib_Success) + print_last_error(); + break; + } + case COMMAND_STOP: { + do_quit = true; + break; + } + case COMMAND_INCR_CH: { + mtx_lock(&data.mtx); + ++data.active_channel; + if (data.active_channel == n_channels) + data.active_channel = 0; + mtx_unlock(&data.mtx); + break; + } + case COMMAND_DECR_CH: { + mtx_lock(&data.mtx); + if (data.active_channel == 0) + data.active_channel = n_channels; + --data.active_channel; + mtx_unlock(&data.mtx); + break; + } + case COMMAND_PLOT_WAVE: { + mtx_lock(&data.mtx); + data.plot_next_wave = true; + mtx_unlock(&data.mtx); + break; + } + case '\n': { + break; + } + default: { + fprintf(stderr, "unknown command [%c]", c); + break; + } + } + } while (!do_quit); + + printf("\nStopping...\t"); + + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/disarmacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // wait the end of the acquisition + // that is going to finish just after the last event + int thrd_ret; + ret = thrd_join(thrd, &thrd_ret); + if (ret != thrd_success || thrd_ret != EXIT_SUCCESS) { + fprintf(stderr, "thrd_join error.\tret %d\tthrd_ret %d\n", ret, thrd_ret); + return EXIT_FAILURE; + } + mtx_destroy(&data.mtx); + cnd_destroy(&data.cnd); + + ret = CAEN_FELib_Close(dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("\nBye!\n"); + + return EXIT_SUCCESS; +} diff --git a/demo/caen-felib-demo-dpp-psd/Makefile b/demo/caen-felib-demo-dpp-psd/Makefile new file mode 100644 index 0000000..5e5bbe3 --- /dev/null +++ b/demo/caen-felib-demo-dpp-psd/Makefile @@ -0,0 +1,20 @@ +TARGET = caen-felib-demo-dpp-psd +CFLAGS = -std=gnu11 -O2 -g -Wall -pthread +LDFLAGS = -pthread +LDLIBS = -lpthread -lCAEN_FELib + +.PHONY: default all clean + +default: $(TARGET) +all: default + +OBJECTS = main.o + +.PRECIOUS: $(TARGET) $(OBJECTS) + +$(TARGET): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $@ + +clean: + -rm -f *.o + -rm -f $(TARGET) diff --git a/demo/caen-felib-demo-dpp-psd/c11threads.h b/demo/caen-felib-demo-dpp-psd/c11threads.h new file mode 100644 index 0000000..cccf430 --- /dev/null +++ b/demo/caen-felib-demo-dpp-psd/c11threads.h @@ -0,0 +1,533 @@ +/* +c11threads + +Authors: + John Tsiombikas - original POSIX threads wrapper + Oliver Old - win32 implementation + +I place this piece of code in the public domain. Feel free to use as you see +fit. I'd appreciate it if you keep my name at the top of the code somewhere, but +whatever. + +Main project site: https://github.com/jtsiomb/c11threads +*/ +#ifndef C11THREADS_H_ +#define C11THREADS_H_ + +/* If you wish to use this with pthread-win32 (i.e. use the POSIX threads wrapper + * instead of the native win32 API implementation of C11 threads), then just + * define C11THREADS_PTHREAD_WIN32 before including this header file. + */ +#if defined(_WIN32) && !defined(C11THREADS_PTHREAD_WIN32) +#define C11THREADS_WIN32 +#endif + +/* If your compiler does not support the inline keyword, or supports it with + * some different variation of prefix or suffix underscores, you can define + * C11THREADS_INLINE before including this header file. + */ +#ifndef C11THREADS_INLINE +/* C99 compilers will have inline */ +#if __STDC_VERSION__ >= 199901L +#define C11THREADS_INLINE inline +/* C++ has inline */ +#elif defined(__cplusplus) +#define C11THREADS_INLINE inline +/* MSVC has inline from VS 2015 but supports __inline in older versions */ +#elif defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define C11THREADS_INLINE inline +#else +#define C11THREADS_INLINE __inline +#endif +/* for every other case, just gamble on having __inline__, and let the user + * define C11THREADS_INLINE if it breaks + */ +#else +#define C11THREADS_INLINE __inline__ +#endif +#endif /* !defined C11THREADS_INLINE */ + +#include + +#ifndef TIME_UTC +#define TIME_UTC 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*thrd_start_t)(void*); +typedef void (*tss_dtor_t)(void*); + +enum { + mtx_plain = 0, + mtx_recursive = 1, + mtx_timed = 2, +}; + +enum { + thrd_success, + thrd_timedout, + thrd_busy, + thrd_error, + thrd_nomem +}; + +#ifndef C11THREADS_WIN32 +/* C11 threads over POSIX threads as thin static inline wrapper functions */ +#include +#include +#include +#include /* for sched_yield */ +#include + +#ifndef thread_local +#define thread_local _Thread_local +#endif + +#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT +#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS + +#ifdef __APPLE__ +/* Darwin doesn't implement timed mutexes currently */ +#define C11THREADS_NO_TIMED_MUTEX +#include +#ifndef __MAC_10_15 +#define C11THREADS_NO_TIMESPEC_GET +#endif +#elif __STDC_VERSION__ < 201112L +#define C11THREADS_NO_TIMESPEC_GET +#endif + +#ifdef C11THREADS_NO_TIMED_MUTEX +#define C11THREADS_TIMEDLOCK_POLL_INTERVAL 5000000 /* 5 ms */ +#endif + +/* types */ +typedef pthread_t thrd_t; +typedef pthread_mutex_t mtx_t; +typedef pthread_cond_t cnd_t; +typedef pthread_key_t tss_t; +typedef pthread_once_t once_flag; + +/* ---- thread management ---- */ + +static C11THREADS_INLINE int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + int res = pthread_create(thr, 0, (void*(*)(void*))func, arg); + if(res == 0) { + return thrd_success; + } + return res == ENOMEM ? thrd_nomem : thrd_error; +} + +static C11THREADS_INLINE void thrd_exit(int res) +{ + pthread_exit((void*)(intptr_t)res); +} + +static C11THREADS_INLINE int thrd_join(thrd_t thr, int *res) +{ + void *retval; + + if(pthread_join(thr, &retval) != 0) { + return thrd_error; + } + if(res) { + *res = (int)(intptr_t)retval; + } + return thrd_success; +} + +static C11THREADS_INLINE int thrd_detach(thrd_t thr) +{ + return pthread_detach(thr) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE thrd_t thrd_current(void) +{ + return pthread_self(); +} + +static C11THREADS_INLINE int thrd_equal(thrd_t a, thrd_t b) +{ + return pthread_equal(a, b); +} + +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out) +{ + if(nanosleep(ts_in, rem_out) < 0) { + if(errno == EINTR) return -1; + return -2; + } + return 0; +} + +static C11THREADS_INLINE void thrd_yield(void) +{ + sched_yield(); +} + +/* ---- mutexes ---- */ + +static C11THREADS_INLINE int mtx_init(mtx_t *mtx, int type) +{ + int res; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + + if(type & mtx_timed) { +#ifdef PTHREAD_MUTEX_TIMED_NP + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP); +#else + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); +#endif + } + if(type & mtx_recursive) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + + res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error; + pthread_mutexattr_destroy(&attr); + return res; +} + +static C11THREADS_INLINE void mtx_destroy(mtx_t *mtx) +{ + pthread_mutex_destroy(mtx); +} + +static C11THREADS_INLINE int mtx_lock(mtx_t *mtx) +{ + int res = pthread_mutex_lock(mtx); + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_trylock(mtx_t *mtx) +{ + int res = pthread_mutex_trylock(mtx); + if(res == EBUSY) { + return thrd_busy; + } + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + int res = 0; +#ifdef C11THREADS_NO_TIMED_MUTEX + /* fake a timedlock by polling trylock in a loop and waiting for a bit */ + struct timeval now; + struct timespec sleeptime; + + sleeptime.tv_sec = 0; + sleeptime.tv_nsec = C11THREADS_TIMEDLOCK_POLL_INTERVAL; + + while((res = pthread_mutex_trylock(mtx)) == EBUSY) { + gettimeofday(&now, NULL); + + if(now.tv_sec > ts->tv_sec || (now.tv_sec == ts->tv_sec && + (now.tv_usec * 1000) >= ts->tv_nsec)) { + return thrd_timedout; + } + + nanosleep(&sleeptime, NULL); + } +#else + if((res = pthread_mutex_timedlock(mtx, ts)) == ETIMEDOUT) { + return thrd_timedout; + } +#endif + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_unlock(mtx_t *mtx) +{ + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; +} + +/* ---- condition variables ---- */ + +static C11THREADS_INLINE int cnd_init(cnd_t *cond) +{ + return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void cnd_destroy(cnd_t *cond) +{ + pthread_cond_destroy(cond); +} + +static C11THREADS_INLINE int cnd_signal(cnd_t *cond) +{ + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_broadcast(cnd_t *cond) +{ + return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ + int res; + + if((res = pthread_cond_timedwait(cond, mtx, ts)) != 0) { + return res == ETIMEDOUT ? thrd_timedout : thrd_error; + } + return thrd_success; +} + +/* ---- thread-specific data ---- */ + +static C11THREADS_INLINE int tss_create(tss_t *key, tss_dtor_t dtor) +{ + return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void tss_delete(tss_t key) +{ + pthread_key_delete(key); +} + +static C11THREADS_INLINE int tss_set(tss_t key, void *val) +{ + return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void *tss_get(tss_t key) +{ + return pthread_getspecific(key); +} + +/* ---- misc ---- */ + +static C11THREADS_INLINE void call_once(once_flag *flag, void (*func)(void)) +{ + pthread_once(flag, func); +} + +#ifdef C11THREADS_NO_TIMESPEC_GET +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base) +{ + struct timeval tv; + + if(base != TIME_UTC) { + return 0; + } + + if(gettimeofday(&tv, 0) == -1) { + return 0; + } + + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + return base; +} +#endif + + +#else /* C11THREADS_WIN32 */ + +/* C11 threads implementation using native Win32 API calls (see c11threads_win32.c) */ + +#ifndef thread_local +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#else +#define thread_local _Thread_local +#endif +#endif + +#define ONCE_FLAG_INIT {0} +#define TSS_DTOR_ITERATIONS 4 + +#ifndef _UCRT +#define C11THREADS_NO_TIMESPEC_GET +#endif + +#ifdef _MSC_VER +#define C11THREADS_MSVC_NORETURN __declspec(noreturn) +#define C11THREADS_GNUC_NORETURN +#elif defined(__GNUC__) +#define C11THREADS_MSVC_NORETURN +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5) +#define C11THREADS_GNUC_NORETURN __attribute__((noreturn)) +#else +#define C11THREADS_GNUC_NORETURN +#endif +#else +#define C11THREADS_MSVC_NORETURN +#define C11THREADS_GNUC_NORETURN +#endif + +/* types */ +typedef unsigned long thrd_t; +typedef struct { + void *debug_info; + long lock_count; + long recursion_count; + void *owning_thread; + void *lock_semaphore; + void *spin_count; +} mtx_t; +typedef void *cnd_t; +typedef unsigned long tss_t; +typedef void *once_flag; +struct _c11threads_win32_timespec32_t { + long tv_sec; + long tv_nsec; +}; +struct _c11threads_win32_timespec64_t { +#ifdef _MSC_VER + __int64 tv_sec; +#else + long long tv_sec; +#endif + long tv_nsec; +}; +#if !defined(_UCRT) && !defined(_TIMESPEC_DEFINED) +#ifdef _USE_32BIT_TIME_T +struct timespec { + long tv_sec; + long tv_nsec; +}; +#elif !defined(_USE_32BIT_TIME_T) +struct timespec { + __int64 tv_sec; + long tv_nsec; +}; +#endif /* !defined(_USE_32BIT_TIME_T) */ +#endif /* !defined(_UCRT) && !defined(_TIMESPEC_DEFINED) */ + +/* Thread functions. */ + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); +/* Win32: Threads not created with thrd_create() need to call this to clean up TSS. */ +C11THREADS_MSVC_NORETURN void thrd_exit(int res) C11THREADS_GNUC_NORETURN; +int thrd_join(thrd_t thr, int *res); +int thrd_detach(thrd_t thr); +thrd_t thrd_current(void); +int thrd_equal(thrd_t a, thrd_t b); +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out); +void thrd_yield(void); + +/* Mutex functions. */ + +int mtx_init(mtx_t *mtx, int type); +void mtx_destroy(mtx_t *mtx); +int mtx_lock(mtx_t *mtx); +int mtx_trylock(mtx_t *mtx); +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); +int mtx_unlock(mtx_t *mtx); + +/* Condition variable functions. */ + +int cnd_init(cnd_t *cond); +void cnd_destroy(cnd_t *cond); +int cnd_signal(cnd_t *cond); +int cnd_broadcast(cnd_t *cond); +int cnd_wait(cnd_t *cond, mtx_t *mtx); +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); + +/* Thread-specific storage functions. */ + +int tss_create(tss_t *key, tss_dtor_t dtor); +void tss_delete(tss_t key); +int tss_set(tss_t key, void *val); +void *tss_get(tss_t key); + +/* One-time callable function. */ + +void call_once(once_flag *flag, void (*func)(void)); + +#ifdef C11THREADS_NO_TIMESPEC_GET +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base); +#endif + +/* Special Win32 functions. */ +/* Win32: Free resources associated with this library. */ +void c11threads_win32_destroy(void); +/* Win32: Register current Win32 thread in c11threads to allow for proper thrd_join(). */ +int c11threads_win32_thrd_self_register(void); +/* Win32: Register Win32 thread by ID in c11threads to allow for proper thrd_join(). */ +int c11threads_win32_thrd_register(unsigned long win32_thread_id); + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) /* Warning C4127: conditional expression is constant */ +#endif + +/* ---- thread management ---- */ + +int _c11threads_win32_thrd_sleep32(const struct _c11threads_win32_timespec32_t *ts_in, struct _c11threads_win32_timespec32_t *rem_out); +int _c11threads_win32_thrd_sleep64(const struct _c11threads_win32_timespec64_t *ts_in, struct _c11threads_win32_timespec64_t *rem_out); +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out) +{ + if (sizeof(ts_in->tv_sec) == 4) { + return _c11threads_win32_thrd_sleep32((const struct _c11threads_win32_timespec32_t*)ts_in, (struct _c11threads_win32_timespec32_t*)rem_out); + } else { + return _c11threads_win32_thrd_sleep64((const struct _c11threads_win32_timespec64_t*)ts_in, (struct _c11threads_win32_timespec64_t*)rem_out); + } +} + +/* ---- mutexes ---- */ + +int _c11threads_win32_mtx_timedlock32(mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts); +int _c11threads_win32_mtx_timedlock64(mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts); +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_mtx_timedlock32(mtx, (const struct _c11threads_win32_timespec32_t*)ts); + } else { + return _c11threads_win32_mtx_timedlock64(mtx, (const struct _c11threads_win32_timespec64_t*)ts); + } +} + +/* ---- condition variables ---- */ + +int _c11threads_win32_cnd_timedwait32(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts); +int _c11threads_win32_cnd_timedwait64(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts); +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_cnd_timedwait32(cond, mtx, (const struct _c11threads_win32_timespec32_t*)ts); + } else { + return _c11threads_win32_cnd_timedwait64(cond, mtx, (const struct _c11threads_win32_timespec64_t*)ts); + } +} + +/* ---- misc ---- */ + +#ifdef C11THREADS_NO_TIMESPEC_GET +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base); +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base); +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_timespec32_get((struct _c11threads_win32_timespec32_t*)ts, base); + } else { + return _c11threads_win32_timespec64_get((struct _c11threads_win32_timespec64_t*)ts, base); + } +} +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif /* C11THREADS_WIN32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* C11THREADS_H_ */ diff --git a/demo/caen-felib-demo-dpp-psd/c11threads_win32.c b/demo/caen-felib-demo-dpp-psd/c11threads_win32.c new file mode 100644 index 0000000..f8badec --- /dev/null +++ b/demo/caen-felib-demo-dpp-psd/c11threads_win32.c @@ -0,0 +1,1147 @@ +/* +Win32 implementation for c11threads. + +Authors: +John Tsiombikas +Oliver Old + +I place this piece of code in the public domain. Feel free to use as you see +fit. I'd appreciate it if you keep my name at the top of the code somewhere, but +whatever. + +Main project site: https://github.com/jtsiomb/c11threads +*/ + +#if defined(_WIN32) && !defined(C11THREADS_PTHREAD_WIN32) + +#ifdef _MSC_VER +/* Map debug malloc and free functions for debug builds. DO NOT CHANGE THE INCLUDE ORDER! */ +#define _CRTDBG_MAP_ALLOC +#include +#include +#endif + +#include "c11threads.h" + +#include +#include +#include + +#ifndef WINVER +#define WINVER 0x0400 /* Windows NT 4.0 */ +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT WINVER +#endif +#define WIN32_LEAN_AND_MEAN +#include + +#define _WIN32_WINNT_VISTA 0x0600 +#define THREAD_QUERY_LIMITED_INFORMATION (0x0800) + + +/* ---- library ---- */ + +typedef void (__stdcall *_c11threads_win32_InitializeConditionVariable_t)(void*); +typedef void (__stdcall *_c11threads_win32_WakeConditionVariable_t)(void*); +typedef void (__stdcall *_c11threads_win32_WakeAllConditionVariable_t)(void*); +typedef int (__stdcall *_c11threads_win32_SleepConditionVariableCS_t)(void*, PCRITICAL_SECTION, unsigned long); +typedef int (__stdcall *_c11threads_win32_InitOnceExecuteOnce_t)(void*, const void*, void*, void**); + +struct _c11threads_win32_thrd_entry_t { + struct _c11threads_win32_thrd_entry_t *next; + void *h; + thrd_t thrd; +}; + +struct _c11threads_win32_tss_dtor_entry_t { + struct _c11threads_win32_tss_dtor_entry_t *next; + tss_dtor_t dtor; + tss_t key; +}; + +static volatile long _c11threads_win32_initialized = 0; +static unsigned short _c11threads_win32_winver; +static _c11threads_win32_InitializeConditionVariable_t _c11threads_win32_InitializeConditionVariable; +static _c11threads_win32_WakeConditionVariable_t _c11threads_win32_WakeConditionVariable; +static _c11threads_win32_WakeAllConditionVariable_t _c11threads_win32_WakeAllConditionVariable; +static _c11threads_win32_SleepConditionVariableCS_t _c11threads_win32_SleepConditionVariableCS; +static _c11threads_win32_InitOnceExecuteOnce_t _c11threads_win32_InitOnceExecuteOnce; +static CRITICAL_SECTION _c11threads_win32_thrd_list_critical_section; +static struct _c11threads_win32_thrd_entry_t *_c11threads_win32_thrd_list_head = NULL; +static CRITICAL_SECTION _c11threads_win32_tss_dtor_list_critical_section; +static struct _c11threads_win32_tss_dtor_entry_t *_c11threads_win32_tss_dtor_list_head = NULL; + +#ifdef _MSC_VER +#pragma warning(push) +/* Warning C4996: 'GetVersion': was declared deprecated */ +/* Warning C28125: The function 'InitializeCriticalSection' must be called from within a try/except block. */ +/* Warning C28159: Consider using 'IsWindows*' instead of 'GetVersion'. Reason: Deprecated. Use VerifyVersionInfo* or IsWindows* macros from VersionHelpers. */ +#pragma warning(disable: 4996 28125 28159) +#endif +static void _c11threads_win32_init(void) +{ + unsigned short os_version; + os_version = (unsigned short)GetVersion(); /* Keep in mind: Maximum version for unmanifested apps is Windows 8 (0x0602). */ + _c11threads_win32_winver = (os_version << 8) | (os_version >> 8); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + void *kernel32; + kernel32 = GetModuleHandleW(L"kernel32.dll"); + if (!kernel32) { + abort(); + } + _c11threads_win32_InitializeConditionVariable = (_c11threads_win32_InitializeConditionVariable_t)GetProcAddress(kernel32, "InitializeConditionVariable"); + if (!_c11threads_win32_InitializeConditionVariable) { + abort(); + } + _c11threads_win32_WakeConditionVariable = (_c11threads_win32_WakeConditionVariable_t)GetProcAddress(kernel32, "WakeConditionVariable"); + if (!_c11threads_win32_WakeConditionVariable) { + abort(); + } + _c11threads_win32_WakeAllConditionVariable = (_c11threads_win32_WakeAllConditionVariable_t)GetProcAddress(kernel32, "WakeAllConditionVariable"); + if (!_c11threads_win32_WakeAllConditionVariable) { + abort(); + } + _c11threads_win32_SleepConditionVariableCS = (_c11threads_win32_SleepConditionVariableCS_t)GetProcAddress(kernel32, "SleepConditionVariableCS"); + if (!_c11threads_win32_SleepConditionVariableCS) { + abort(); + } + _c11threads_win32_InitOnceExecuteOnce = (_c11threads_win32_InitOnceExecuteOnce_t)GetProcAddress(kernel32, "InitOnceExecuteOnce"); + if (!_c11threads_win32_InitOnceExecuteOnce) { + abort(); + } + } + InitializeCriticalSection(&_c11threads_win32_thrd_list_critical_section); + InitializeCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static void _c11threads_win32_ensure_initialized(void) +{ + if (InterlockedCompareExchange(&_c11threads_win32_initialized, 1, 0) == 0) { + _c11threads_win32_init(); + InterlockedExchange(&_c11threads_win32_initialized, 2); + } else { +#ifdef _MSC_VER +#pragma warning(suppress: 28112) /* Warning C28112: A variable (_c11threads_win32_initialized) which is accessed via an Interlocked function must always be accessed via an Interlocked function. */ +#endif + while (_c11threads_win32_initialized == 1) { + Sleep(0); + } + } +} + +void c11threads_win32_destroy(void) +{ + struct _c11threads_win32_thrd_entry_t *thrd_entry; + struct _c11threads_win32_thrd_entry_t *thrd_entry_temp; + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry; + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry_temp; + + if (_c11threads_win32_initialized) { + DeleteCriticalSection(&_c11threads_win32_thrd_list_critical_section); + DeleteCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + thrd_entry = _c11threads_win32_thrd_list_head; + while (thrd_entry) { + thrd_entry_temp = thrd_entry->next; + CloseHandle(thrd_entry->h); + free(thrd_entry); + thrd_entry = thrd_entry_temp; + } + + tss_dtor_entry = _c11threads_win32_tss_dtor_list_head; + while (tss_dtor_entry) { + tss_dtor_entry_temp = tss_dtor_entry->next; + TlsFree(tss_dtor_entry->key); + free(tss_dtor_entry); + tss_dtor_entry = tss_dtor_entry_temp; + } + + _c11threads_win32_initialized = 0; + _c11threads_win32_thrd_list_head = NULL; + _c11threads_win32_tss_dtor_list_head = NULL; + } +} + +/* ---- utilities ---- */ + +static int _c11threads_win32_util_is_timespec32_valid(const struct _c11threads_win32_timespec32_t *ts) +{ + return ts->tv_sec >= 0 && ts->tv_nsec >= 0 && ts->tv_nsec <= 999999999; +} + +static int _c11threads_win32_util_is_timespec64_valid(const struct _c11threads_win32_timespec64_t *ts) +{ + return ts->tv_sec >= 0 && ts->tv_nsec >= 0 && ts->tv_nsec <= 999999999; +} + +/* Precondition: 'ts' validated. */ +static __int64 _c11threads_win32_util_timespec32_to_file_time(const struct _c11threads_win32_timespec32_t *ts) +{ + unsigned __int64 sec_res; + unsigned __int64 nsec_res; + + sec_res = (unsigned __int64)ts->tv_sec * (unsigned __int64)10000000; + + /* Add another 100 ns if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 100UL + !!((unsigned long)ts->tv_nsec % 100UL); + + return sec_res + nsec_res; +} + +/* Precondition: 'ts' validated. */ +static __int64 _c11threads_win32_util_timespec64_to_file_time(const struct _c11threads_win32_timespec64_t *ts, size_t *periods) +{ + unsigned __int64 sec_res; + unsigned __int64 nsec_res; + unsigned __int64 res; + + *periods = (unsigned long)((unsigned __int64)ts->tv_sec / (unsigned __int64)922337203685); + sec_res = ((unsigned __int64)ts->tv_sec % (unsigned __int64)922337203685) * (unsigned __int64)10000000; + + /* Add another 100 ns if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 100UL + !!((unsigned long)ts->tv_nsec % 100UL); + + /* 64-bit time_t may cause overflow. */ + if (nsec_res > (unsigned __int64) - 1 - sec_res) { + ++*periods; + nsec_res -= (unsigned __int64) - 1 - sec_res; + sec_res = 0; + } + + res = sec_res + nsec_res; + + if (*periods && !res) { + --*periods; + return (__int64)9223372036850000000; + } + + return res; +} + +/* Precondition: 'ts' validated. */ +static int _c11threads_win32_util_timespec32_to_milliseconds(const struct _c11threads_win32_timespec32_t *ts, unsigned long *ms) +{ + unsigned long sec_res; + unsigned long nsec_res; + + /* Overflow. */ + if ((unsigned long)ts->tv_sec > (INFINITE - 1UL) / 1000UL) { + return 0; + } + + sec_res = (unsigned long)ts->tv_sec * 1000UL; + /* Add another millisecond if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 1000000UL + !!((unsigned long)ts->tv_nsec % 1000000UL); + + /* Overflow. */ + if (nsec_res > INFINITE - 1UL - sec_res) { + return 0; + } + + *ms = sec_res + nsec_res; + return 1; +} + +/* Precondition: 'ts' validated. */ +static int _c11threads_win32_util_timespec64_to_milliseconds(const struct _c11threads_win32_timespec64_t *ts, unsigned long *ms) +{ + unsigned long sec_res; + unsigned long nsec_res; + + /* Overflow. */ + if ((unsigned __int64)ts->tv_sec > (INFINITE - 1UL) / 1000UL) { + return 0; + } + + sec_res = (unsigned long)ts->tv_sec * 1000UL; + /* Add another millisecond if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 1000000UL + !!((unsigned long)ts->tv_nsec % 1000000UL); + + /* Overflow. */ + if (nsec_res > INFINITE - 1UL - sec_res) { + return 0; + } + + *ms = sec_res + nsec_res; + return 1; +} + +/* Precondition: 'current_time' and 'end_time' validated. */ +static unsigned long _c11threads_win32_util_timepoint_to_millisecond_timespan32(const struct _c11threads_win32_timespec32_t *current_time, const struct _c11threads_win32_timespec32_t *end_time, int *clamped) { + unsigned long wait_time; + struct _c11threads_win32_timespec32_t ts; + + *clamped = 0; + if (current_time->tv_sec > end_time->tv_sec || (current_time->tv_sec == end_time->tv_sec && current_time->tv_nsec >= end_time->tv_nsec)) { + wait_time = 0; + } else { + ts.tv_sec = end_time->tv_sec - current_time->tv_sec; + ts.tv_nsec = end_time->tv_nsec - current_time->tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000; + } + + if (!_c11threads_win32_util_timespec32_to_milliseconds(&ts, &wait_time)) { + /* Clamp wait_time. Pretend we've had a spurious wakeup if expired. */ + wait_time = INFINITE - 1; + *clamped = 1; + } + } + + return wait_time; +} + +/* Precondition: 'current_time' and 'end_time' validated. */ +static unsigned long _c11threads_win32_util_timepoint_to_millisecond_timespan64(const struct _c11threads_win32_timespec64_t *current_time, const struct _c11threads_win32_timespec64_t *end_time, int *clamped) { + unsigned long wait_time; + struct _c11threads_win32_timespec64_t ts; + + *clamped = 0; + if (current_time->tv_sec > end_time->tv_sec || (current_time->tv_sec == end_time->tv_sec && current_time->tv_nsec >= end_time->tv_nsec)) { + wait_time = 0; + } else { + ts.tv_sec = end_time->tv_sec - current_time->tv_sec; + ts.tv_nsec = end_time->tv_nsec - current_time->tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000; + } + + if (!_c11threads_win32_util_timespec64_to_milliseconds(&ts, &wait_time)) { + /* Clamp wait_time. Pretend we've had a spurious wakeup if expired. */ + wait_time = INFINITE - 1; + *clamped = 1; + } + } + + return wait_time; +} + +#if defined(C11THREADS_NO_TIMESPEC_GET) || !defined(_MSC_VER) +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base) +{ + FILETIME file_time; + ULARGE_INTEGER li; + + if (base != TIME_UTC) { + return 0; + } + + GetSystemTimeAsFileTime(&file_time); + + li.LowPart = file_time.dwLowDateTime; + li.HighPart = file_time.dwHighDateTime; + + /* Also subtract difference between FILETIME and UNIX time epoch. It's 369 years by the way. */ + ts->tv_sec = (long)(li.QuadPart / (unsigned __int64)10000000 - (unsigned __int64)11644473600); + ts->tv_nsec = (long)(li.QuadPart % (unsigned __int64)10000000) * 100; + + return base; +} + +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base) +{ + FILETIME file_time; + ULARGE_INTEGER li; + + if (base != TIME_UTC) { + return 0; + } + + GetSystemTimeAsFileTime(&file_time); + + li.LowPart = file_time.dwLowDateTime; + li.HighPart = file_time.dwHighDateTime; + + /* Also subtract difference between FILETIME and UNIX time epoch. It's 369 years by the way. */ + ts->tv_sec = li.QuadPart / (unsigned __int64)10000000 - (unsigned __int64)11644473600; + ts->tv_nsec = (long)(li.QuadPart % (unsigned __int64)10000000) * 100; + + return base; +} +#else +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base) +{ + return _timespec32_get((struct _timespec32*)ts, base); +} + +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base) +{ + return _timespec64_get((struct _timespec64*)ts, base); +} +#endif + +/* ---- thread management ---- */ + +static int _c11threads_win32_thrd_register(thrd_t thrd, HANDLE h) +{ + struct _c11threads_win32_thrd_entry_t *thread_entry; + + thread_entry = malloc(sizeof(*thread_entry)); + if (!thread_entry) { + return 0; + } + + thread_entry->thrd = thrd; + thread_entry->h = h; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + thread_entry->next = _c11threads_win32_thrd_list_head; + _c11threads_win32_thrd_list_head = thread_entry; + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + return 1; +} + +static void *_c11threads_win32_thrd_pop_entry(thrd_t thrd) +{ + void *h; + struct _c11threads_win32_thrd_entry_t *prev; + struct _c11threads_win32_thrd_entry_t *curr; + struct _c11threads_win32_thrd_entry_t *next; + + h = NULL; + prev = NULL; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + curr = _c11threads_win32_thrd_list_head; + while (curr) + { + if (curr->thrd == thrd) { + h = curr->h; + next = curr->next; + if (prev) { + prev->next = next; + } else { + _c11threads_win32_thrd_list_head = next; + } + break; + } + + prev = curr; + curr = curr->next; + } + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + free(curr); + return h; +} + +static void _c11threads_win32_thrd_run_tss_dtors(void) +{ + int ran_dtor; + size_t i; + struct _c11threads_win32_tss_dtor_entry_t *prev; + struct _c11threads_win32_tss_dtor_entry_t *curr; + struct _c11threads_win32_tss_dtor_entry_t *next; + void *val; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + ran_dtor = 1; + for (i = 0; i < TSS_DTOR_ITERATIONS && ran_dtor; ++i) { + ran_dtor = 0; + prev = NULL; + curr = _c11threads_win32_tss_dtor_list_head; + + while (curr) { + val = TlsGetValue(curr->key); + if (val) { + TlsSetValue(curr->key, NULL); + curr->dtor(val); + ran_dtor = 1; + } else if (GetLastError() != ERROR_SUCCESS) { + next = curr->next; + free(curr); + if (prev) { + prev->next = next; + } else { + _c11threads_win32_tss_dtor_list_head = next; + } + curr = next; + continue; + } + + curr = curr->next; + } + } + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); +} + +int c11threads_win32_thrd_self_register(void) +{ + unsigned long desired_access; + void *process; + void *thread; + + desired_access = SYNCHRONIZE | THREAD_QUERY_INFORMATION; + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + desired_access = SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION; + } + + process = GetCurrentProcess(); + thread = GetCurrentThread(); + if (!DuplicateHandle(process, thread, process, &thread, desired_access, 0, 0)) { + return thrd_error; + } + if (!_c11threads_win32_thrd_register(GetCurrentThreadId(), thread)) { + CloseHandle(thread); + return thrd_nomem; + } + return thrd_success; +} + +int c11threads_win32_thrd_register(unsigned long win32_thread_id) +{ + /* XXX temporary hack to make this build on MSVC6. Investigate further */ +#ifdef _PROCESSTHREADSAPI_H_ + unsigned long desired_access; + void *h; + + desired_access = SYNCHRONIZE | THREAD_QUERY_INFORMATION; + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + desired_access = SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION; + } + + h = OpenThread(desired_access, 0, win32_thread_id); + if (!h) { + return thrd_error; + } + if (!_c11threads_win32_thrd_register(win32_thread_id, h)) { + CloseHandle(h); + return thrd_nomem; + } +#endif + return thrd_success; +} + +struct _c11threads_win32_thrd_start_thunk_parameters_t { + thrd_start_t func; + void *arg; +}; + +static int __stdcall _c11threads_win32_thrd_start_thunk(struct _c11threads_win32_thrd_start_thunk_parameters_t *start_parameters) +{ + int res; + struct _c11threads_win32_thrd_start_thunk_parameters_t local_start_params; + local_start_params = *start_parameters; + free(start_parameters); + res = local_start_params.func(local_start_params.arg); + _c11threads_win32_thrd_run_tss_dtors(); + return res; +} + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + struct _c11threads_win32_thrd_start_thunk_parameters_t *thread_start_params; + struct _c11threads_win32_thrd_entry_t *thread_entry; + void *h; + + thread_start_params = malloc(sizeof(*thread_start_params)); + if (!thread_start_params) { + return thrd_nomem; + } + + thread_start_params->func = func; + thread_start_params->arg = arg; + + thread_entry = malloc(sizeof(*thread_entry)); + if (!thread_entry) { + free(thread_start_params); + return thrd_nomem; + } + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + h = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)_c11threads_win32_thrd_start_thunk, thread_start_params, 0, thr); + if (!h) { + unsigned long error; + error = GetLastError(); + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + free(thread_start_params); + free(thread_entry); + return error == ERROR_NOT_ENOUGH_MEMORY ? thrd_nomem : thrd_error; + } + thread_entry->next = _c11threads_win32_thrd_list_head; + thread_entry->h = h; + thread_entry->thrd = *thr; + _c11threads_win32_thrd_list_head = thread_entry; + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + return thrd_success; +} + +void thrd_exit(int res) +{ + _c11threads_win32_thrd_run_tss_dtors(); + ExitThread(res); +} + +int thrd_join(thrd_t thr, int *res) +{ + int ret; + void *h; + + ret = thrd_error; + h = _c11threads_win32_thrd_pop_entry(thr); + if (h) { + if (WaitForSingleObject(h, INFINITE) == WAIT_OBJECT_0 && (!res || GetExitCodeThread(h, (unsigned long*)res))) { + ret = thrd_success; + } + + CloseHandle(h); + } + + return ret; +} + +int thrd_detach(thrd_t thr) +{ + void *h; + h = _c11threads_win32_thrd_pop_entry(thr); + return h && CloseHandle(h) ? thrd_success : thrd_error; +} + +thrd_t thrd_current(void) +{ + return GetCurrentThreadId(); +} + +static int _c11threads_win32_sleep_common(__int64 file_time_in) +{ + void *timer; + unsigned long error; + LARGE_INTEGER due_time; + + assert(file_time_in >= 0); + + timer = CreateWaitableTimerW(NULL, 1, NULL); + if (!timer) { + error = GetLastError(); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + due_time.QuadPart = -file_time_in; + if (!SetWaitableTimer(timer, &due_time, 0, NULL, NULL, 0)) { + error = GetLastError(); + CloseHandle(timer); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) { + error = GetLastError(); + CloseHandle(timer); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + CloseHandle(timer); + return 0; /* Success. */ +} + +int _c11threads_win32_thrd_sleep32(const struct _c11threads_win32_timespec32_t *ts_in, struct _c11threads_win32_timespec32_t *rem_out) +{ + __int64 file_time; + int res; + + (void)rem_out; + + if (!_c11threads_win32_util_is_timespec32_valid(ts_in)) { + return -ERROR_INVALID_PARAMETER; + } + + file_time = _c11threads_win32_util_timespec32_to_file_time(ts_in); + if (file_time < 0) { + return -ERROR_INVALID_PARAMETER; + } + + res = _c11threads_win32_sleep_common(file_time); + + return res; +} + +int _c11threads_win32_thrd_sleep64(const struct _c11threads_win32_timespec64_t *ts_in, struct _c11threads_win32_timespec64_t *rem_out) +{ + __int64 file_time; + size_t periods; + int res; + + (void)rem_out; + + if (!_c11threads_win32_util_is_timespec64_valid(ts_in)) { + return -ERROR_INVALID_PARAMETER; + } + + file_time = _c11threads_win32_util_timespec64_to_file_time(ts_in, &periods); + if (file_time < 0) { + return -ERROR_INVALID_PARAMETER; + } + +restart_sleep: + res = _c11threads_win32_sleep_common(file_time); + + if (!res && periods) { + --periods; + file_time = (__int64)9223372036850000000; + goto restart_sleep; + } + + return res; +} + +void thrd_yield(void) +{ + SwitchToThread(); +} + +/* ---- mutexes ---- */ + +int mtx_init(mtx_t *mtx, int type) +{ + (void)type; +#ifdef _MSC_VER +#pragma warning(suppress: 28125) /* Warning C28125: The function 'InitializeCriticalSection' must be called from within a try/except block. */ +#endif + InitializeCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +void mtx_destroy(mtx_t *mtx) +{ + DeleteCriticalSection((PCRITICAL_SECTION)mtx); +} + +int mtx_lock(mtx_t *mtx) +{ + EnterCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +int mtx_trylock(mtx_t *mtx) +{ + return TryEnterCriticalSection((PCRITICAL_SECTION)mtx) ? thrd_success : thrd_busy; +} + +int _c11threads_win32_mtx_timedlock32(mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts) +{ + int success; + struct _c11threads_win32_timespec32_t ts_current; + + if (!_c11threads_win32_util_is_timespec32_valid(ts)) { + return thrd_error; + } + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + while (!success) { + if (!_c11threads_win32_timespec32_get(&ts_current, TIME_UTC)) { + return thrd_error; + } + + if (ts_current.tv_sec > ts->tv_sec || (ts_current.tv_sec == ts->tv_sec && ts_current.tv_nsec >= ts->tv_nsec)) { + return thrd_timedout; + } + + Sleep(0); + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + } + + return thrd_success; +} + +int _c11threads_win32_mtx_timedlock64(mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts) +{ + int success; + struct _c11threads_win32_timespec64_t ts_current; + + if (!_c11threads_win32_util_is_timespec64_valid(ts)) { + return thrd_error; + } + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + while (!success) { + if (!_c11threads_win32_timespec64_get(&ts_current, TIME_UTC)) { + return thrd_error; + } + + if (ts_current.tv_sec > ts->tv_sec || (ts_current.tv_sec == ts->tv_sec && ts_current.tv_nsec >= ts->tv_nsec)) { + return thrd_timedout; + } + + Sleep(0); + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + } + + return thrd_success; +} + +int mtx_unlock(mtx_t *mtx) +{ + LeaveCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +/* ---- condition variables ---- */ + +struct _c11threads_win32_cnd_t { + void *mutex; + void *signal_sema; + void *broadcast_event; + size_t wait_count; +}; + +int cnd_init(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_InitializeConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + + cnd = malloc(sizeof(*cnd)); + if (!cnd) { + return thrd_nomem; + } + + cnd->mutex = CreateMutexW(NULL, 0, NULL); + if (cnd->mutex) { + cnd->signal_sema = CreateSemaphoreW(NULL, 0, 0x7fffffff, NULL); + if (cnd->signal_sema) { + cnd->broadcast_event = CreateEventW(NULL, 1, 0, NULL); + if (cnd->broadcast_event) { + cnd->wait_count = 0; + *cond = cnd; + return thrd_success; + } + CloseHandle(cnd->signal_sema); + } + CloseHandle(cnd->mutex); + } + + free(cnd); + return thrd_error; + } +} + +void cnd_destroy(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver < _WIN32_WINNT_VISTA) { + struct _c11threads_win32_cnd_t *cnd; + cnd = *cond; + assert(!cnd->wait_count); + CloseHandle(cnd->mutex); + CloseHandle(cnd->signal_sema); + CloseHandle(cnd->broadcast_event); + free(cnd); + } +} + +int cnd_signal(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_WakeConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + int success; + unsigned long wait_status; + + cnd = *cond; + + success = 0; + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_OBJECT_0) { + success = 1; + } else if (wait_status == WAIT_ABANDONED) { + abort(); + } + + if (success) { + if (cnd->wait_count) { + success = ReleaseSemaphore(cnd->signal_sema, 1, NULL) || GetLastError() == ERROR_TOO_MANY_POSTS; + } + if (!ReleaseMutex(cnd->mutex)) { + success = 0; + } + } + + return success ? thrd_success : thrd_error; + } +} + +int cnd_broadcast(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_WakeAllConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + int success; + unsigned long wait_status; + + cnd = *cond; + + success = 0; + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_OBJECT_0) { + success = 1; + } else if (wait_status == WAIT_ABANDONED) { + abort(); + } + + if (success) { + if (cnd->wait_count) { + success = SetEvent(cnd->broadcast_event); + } + if (!ReleaseMutex(cnd->mutex)) { + success = 0; + } + } + + return success ? thrd_success : thrd_error; + } +} + +static int _c11threads_win32_cnd_wait_common(cnd_t *cond, mtx_t *mtx, unsigned long wait_time, int clamped) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + if (_c11threads_win32_SleepConditionVariableCS(cond, (PCRITICAL_SECTION)mtx, wait_time)) { + return thrd_success; + } + + if (GetLastError() == ERROR_TIMEOUT) { + return clamped ? thrd_success : thrd_timedout; + } + + return thrd_error; + } else { + struct _c11threads_win32_cnd_t *cnd; + unsigned long wait_status; + unsigned long wait_status_2; + int res; + + cnd = *cond; + + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_ABANDONED) { + abort(); + } else if (wait_status != WAIT_OBJECT_0) { + return thrd_error; + } + LeaveCriticalSection((PCRITICAL_SECTION)mtx); + ++cnd->wait_count; + if (!ReleaseMutex(cnd->mutex)) { + abort(); + } + + wait_status = WaitForMultipleObjects(2, &cnd->signal_sema /* and cnd->broadcast_event */, 0, wait_time); + + if (WaitForSingleObject(cnd->mutex, INFINITE) != WAIT_OBJECT_0) { + abort(); + } + --cnd->wait_count; + if (!cnd->wait_count) { + do { + wait_status_2 = WaitForSingleObject(cnd->signal_sema, 0); + } while (wait_status_2 == WAIT_OBJECT_0); + if (wait_status_2 != WAIT_TIMEOUT) { + abort(); + } + + if (!ResetEvent(cnd->broadcast_event)) { + abort(); + } + } + if (!ReleaseMutex(cnd->mutex)) { + abort(); + } + + res = thrd_success; + if (wait_status == WAIT_TIMEOUT) { + if (!clamped) { + res = thrd_timedout; + } + } else if (wait_status != WAIT_OBJECT_0 && wait_status != WAIT_OBJECT_0 + 1) { + res = thrd_error; + } + + EnterCriticalSection((PCRITICAL_SECTION)mtx); + return res; + } +} + +int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return _c11threads_win32_cnd_wait_common(cond, mtx, INFINITE, 0); +} + +int _c11threads_win32_cnd_timedwait32(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts) +{ + struct _c11threads_win32_timespec32_t current_time; + unsigned long wait_time; + int clamped; + + if (!_c11threads_win32_util_is_timespec32_valid(ts)) { + return thrd_error; + } + + if (!_c11threads_win32_timespec32_get(¤t_time, TIME_UTC)) { + return thrd_error; + } + + wait_time = _c11threads_win32_util_timepoint_to_millisecond_timespan32(¤t_time, ts, &clamped); + + return _c11threads_win32_cnd_wait_common(cond, mtx, wait_time, clamped); +} + +int _c11threads_win32_cnd_timedwait64(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts) +{ + struct _c11threads_win32_timespec64_t current_time; + unsigned long wait_time; + int clamped; + + if (!_c11threads_win32_util_is_timespec64_valid(ts)) { + return thrd_error; + } + + if (!_c11threads_win32_timespec64_get(¤t_time, TIME_UTC)) { + return thrd_error; + } + + wait_time = _c11threads_win32_util_timepoint_to_millisecond_timespan64(¤t_time, ts, &clamped); + + return _c11threads_win32_cnd_wait_common(cond, mtx, wait_time, clamped); +} + +/* ---- thread-specific data ---- */ + +static int _c11threads_win32_tss_register(tss_t key, tss_dtor_t dtor) { + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry; + + tss_dtor_entry = malloc(sizeof(*tss_dtor_entry)); + if (!tss_dtor_entry) { + return 0; + } + + tss_dtor_entry->key = key; + tss_dtor_entry->dtor = dtor; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + tss_dtor_entry->next = _c11threads_win32_tss_dtor_list_head; + _c11threads_win32_tss_dtor_list_head = tss_dtor_entry; + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + return 1; +} + +static void _c11threads_win32_tss_deregister(tss_t key) { + struct _c11threads_win32_tss_dtor_entry_t *prev; + struct _c11threads_win32_tss_dtor_entry_t *curr; + struct _c11threads_win32_tss_dtor_entry_t *next; + + prev = NULL; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + curr = _c11threads_win32_tss_dtor_list_head; + while (curr) + { + if (curr->key == key) { + next = curr->next; + if (prev) { + prev->next = next; + } else { + _c11threads_win32_tss_dtor_list_head = next; + } + break; + } + + prev = curr; + curr = curr->next; + } + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + free(curr); +} + +int tss_create(tss_t *key, tss_dtor_t dtor) +{ + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) { + return thrd_error; + } + if (dtor && !_c11threads_win32_tss_register(*key, dtor)) { + TlsFree(*key); + return thrd_error; + } + return thrd_success; +} + +void tss_delete(tss_t key) +{ + _c11threads_win32_tss_deregister(key); + TlsFree(key); +} + +int tss_set(tss_t key, void *val) +{ + return TlsSetValue(key, val) ? thrd_success : thrd_error; +} + +void *tss_get(tss_t key) +{ + return TlsGetValue(key); +} + +/* ---- misc ---- */ + +static int __stdcall _c11threads_win32_call_once_thunk(void *init_once, void (*func)(void), void **context) +{ + (void)init_once; + (void)context; + func(); + return 1; +} + +void call_once(once_flag *flag, void (*func)(void)) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { +#ifdef _MSC_VER +#pragma warning(push) +/* Warning C4054: 'type cast' : from function pointer 'int (__stdcall *)(void *,void (__cdecl *)(void),void **)' to data pointer 'const void *' */ +/* Warning C4054: 'type cast' : from function pointer 'void (__cdecl *)(void)' to data pointer 'void *' */ +#pragma warning(disable: 4054) +#endif + _c11threads_win32_InitOnceExecuteOnce((void*)flag, (const void*)_c11threads_win32_call_once_thunk, (void*)func, NULL); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } else { + if (InterlockedCompareExchange((long*)flag, 1, 0) == 0) { + func(); + InterlockedExchange((long*)flag, 2); + } else { + while (*(volatile long*)flag == 1) { + Sleep(0); + } + } + } +} + +#endif diff --git a/demo/caen-felib-demo-dpp-psd/caen-felib-demo-dpp-psd.vcxproj b/demo/caen-felib-demo-dpp-psd/caen-felib-demo-dpp-psd.vcxproj new file mode 100644 index 0000000..99338c8 --- /dev/null +++ b/demo/caen-felib-demo-dpp-psd/caen-felib-demo-dpp-psd.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {ba2b592c-06f2-4c22-8f84-bb3c3593209b} + caenfelibdemodpppsd + 10.0.16299.0 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-dpp-psd/caen-felib-demo-dpp-psd.vcxproj.filters b/demo/caen-felib-demo-dpp-psd/caen-felib-demo-dpp-psd.vcxproj.filters new file mode 100644 index 0000000..ef7db9a --- /dev/null +++ b/demo/caen-felib-demo-dpp-psd/caen-felib-demo-dpp-psd.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-dpp-psd/main.c b/demo/caen-felib-demo-dpp-psd/main.c new file mode 100644 index 0000000..0214cfe --- /dev/null +++ b/demo/caen-felib-demo-dpp-psd/main.c @@ -0,0 +1,885 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +* SPDX-License-Identifier: MIT-0 +* +***************************************************************************//*! +* +* \file main.c +* \brief CAEN Open FPGA Digitzers DPP-PSD demo +* \author Giovanni Cerretani, Alberto Potenza +* +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +// windows or C11 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_THREADS__) +#include +#else +#include "c11threads.h" +#endif + +#include + +// Basic hardcoded configuration +#define COMMAND_TRIGGER 't' +#define COMMAND_STOP 'q' +#define COMMAND_INCR_CH '+' +#define COMMAND_DECR_CH '-' +#define COMMAND_PLOT_WAVE 'w' +#define MAX_NUMBER_OF_SAMPLES (4095 * 2) +#define MAX_NUMBER_OF_BINS (1U << 16) +#define EVT_FILE_NAME "EventInfo.txt" +#define EVT_FILE_ENABLED true +#define HISTO_FILE_NAME "Histogram_%zu.txt" +#define WAVE_FILE_NAME "Waveform.txt" +#define DATA_FORMAT " \ + [ \ + { \"name\" : \"CHANNEL\", \"type\" : \"U8\" }, \ + { \"name\" : \"TIMESTAMP\", \"type\" : \"U64\" }, \ + { \"name\" : \"FINE_TIMESTAMP\", \"type\" : \"U16\" }, \ + { \"name\" : \"ENERGY\", \"type\" : \"U16\" }, \ + { \"name\" : \"ENERGY_SHORT\", \"type\" : \"U16\" }, \ + { \"name\" : \"ANALOG_PROBE_1\", \"type\" : \"I32\", \"dim\" : 1 }, \ + { \"name\" : \"ANALOG_PROBE_2\", \"type\" : \"I32\", \"dim\" : 1 }, \ + { \"name\" : \"DIGITAL_PROBE_1\", \"type\" : \"U8\", \"dim\" : 1 }, \ + { \"name\" : \"DIGITAL_PROBE_2\", \"type\" : \"U8\", \"dim\" : 1 }, \ + { \"name\" : \"DIGITAL_PROBE_3\", \"type\" : \"U8\", \"dim\" : 1 }, \ + { \"name\" : \"DIGITAL_PROBE_4\", \"type\" : \"U8\", \"dim\" : 1 }, \ + { \"name\" : \"ANALOG_PROBE_1_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"ANALOG_PROBE_2_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"DIGITAL_PROBE_1_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"DIGITAL_PROBE_2_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"DIGITAL_PROBE_3_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"DIGITAL_PROBE_4_TYPE\", \"type\" : \"U8\" }, \ + { \"name\" : \"WAVEFORM_SIZE\", \"type\" : \"SIZE_T\" }, \ + { \"name\" : \"FLAGS_LOW_PRIORITY\", \"type\" : \"U16\"}, \ + { \"name\" : \"FLAGS_HIGH_PRIORITY\", \"type\" : \"U16\" }, \ + { \"name\" : \"EVENT_SIZE\", \"type\" : \"SIZE_T\" } \ + ] \ +" + +// Utilities +#define ARRAY_SIZE(X) (sizeof(X)/sizeof((X)[0])) + +#ifdef _WIN32 // Windows +#include +#define GNUPLOT "pgnuplot.exe" +#else // Linux +#include +#include +#define GNUPLOT "gnuplot" +#define _popen(command, type) popen(command, type) +#define _pclose(command) pclose(command) +// Linux replacement for non standard _getch +static int _getch() { + struct termios oldattr; + if (tcgetattr(STDIN_FILENO, &oldattr) == -1) perror(NULL); + struct termios newattr = oldattr; + newattr.c_lflag &= ~(ICANON | ECHO); + if (tcsetattr(STDIN_FILENO, TCSANOW, &newattr) == -1) perror(NULL); + const int ch = getchar(); + if (tcsetattr(STDIN_FILENO, TCSANOW, &oldattr) == -1) perror(NULL); + return ch; +} +#endif + +static unsigned long long value_to_ull(const char* value) { + char* value_end; + const unsigned long long ret = strtoull(value, &value_end, 0); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtoull error\n"); + return ret; +} + +static double value_to_d(const char* value) { + char* value_end; + const double ret = strtod(value, &value_end); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtod error\n"); + return ret; +} + +static int print_last_error(void) { + char msg[1024]; + int ec = CAEN_FELib_GetLastError(msg); + if (ec != CAEN_FELib_Success) { + fprintf(stderr, "%s failed\n", __func__); + return ec; + } + fprintf(stderr, "last error: %s\n", msg); + return ec; +} + +static int connect_to_digitizer(uint64_t* dev_handle, int argc, char* argv[]) { + const char* path; + char local_path[256]; + printf("device path: "); + if (argc == 2) { + path = argv[1]; + puts(path); + } else { + while (fgets(local_path, sizeof(local_path), stdin) == NULL); + local_path[strcspn(local_path, "\r\n")] = '\0'; // remove newline added by fgets + path = local_path; + } + return CAEN_FELib_Open(path, dev_handle); +} + +static int get_n_channels(uint64_t dev_handle, size_t* n_channels) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + *n_channels = (size_t)value_to_ull(value); + return ret; +} + +static int print_digitizer_details(uint64_t dev_handle) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/ModelName", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Model name:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/SerialNum", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Serial number:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_Nbit", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC bits:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Channels:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_SamplRate", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC rate:\t%f Msps\n", value_to_d(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/cupver", value); + if (ret != CAEN_FELib_Success) return ret; + printf("CUP version:\t%s\n", value); + return ret; +} + +static int configure_digitizer(uint64_t dev_handle, size_t n_channels) { + + int ret; + char par_name[256]; + + // Channel settings + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChEnable", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "true"); + if (ret != CAEN_FELib_Success) return ret; + + // Global trigger configuration + ret = CAEN_FELib_SetValue(dev_handle, "/par/GlobalTriggerSource", "SwTrg | TestPulse"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulsePeriod", "100000000"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulseWidth", "16"); + if (ret != CAEN_FELib_Success) return ret; + + // Wave configuration + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChRecordLengthS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "512"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveTriggerSource", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "GlobalTriggerSource"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveAnalogProbe0", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "ADCInput"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveAnalogProbe1", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "CFDFilter"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveDigitalProbe0", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "Trigger"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveDigitalProbe1", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "LongGate"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveDigitalProbe2", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "ShortGate"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/WaveDigitalProbe3", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "ChargeReady"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChPreTriggerS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "200"); + if (ret != CAEN_FELib_Success) return ret; + + // Event configuration + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EventTriggerSource", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "GlobalTriggerSource"); + if (ret != CAEN_FELib_Success) return ret; + + // Filter parameters + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/CFDDelayS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "4"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/CFDFraction", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "50"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/TriggerThr", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "3"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/PulsePolarity", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "Positive"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/SmoothingFactor", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "2"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/TimeFilterSmoothing", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "Enabled"); + if (ret != CAEN_FELib_Success) return ret; + + // Energy parameters + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/GateLongLengthS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "100"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/GateShortLengthS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "10"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/GateOffsetS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "8"); + if (ret != CAEN_FELib_Success) return ret; + + return ret; + +} + +static int configure_endpoint(uint64_t ep_handle) { + int ret; + // conigure endpoint + uint64_t ep_folder_handle; + ret = CAEN_FELib_GetParentHandle(ep_handle, NULL, &ep_folder_handle); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(ep_folder_handle, "/par/activeendpoint", "dpppsd"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetReadDataFormat(ep_handle, DATA_FORMAT); + if (ret != CAEN_FELib_Success) return ret; + return ret; +} + +struct counters { + size_t total_size; + size_t n_events; + time_t t_begin; +}; + +struct event { + uint8_t channel; + uint64_t timestamp; + double timestamp_us; + uint16_t fine_timestamp; + uint16_t energy; + uint16_t energy_short; + uint16_t flags_low_priority; + uint16_t flags_high_priority; + size_t event_size; + int32_t* analog_probes[2]; + uint8_t* digital_probes[4]; + uint8_t analog_probes_type[2]; + uint8_t digital_probes_type[4]; + size_t n_allocated_samples; + size_t n_samples; +}; + +struct histograms { + uint32_t** histogram; + size_t n_allocated_channels; + size_t n_allocated_bins; +}; + +struct acq_data { + uint64_t dev_handle; + mtx_t mtx; + cnd_t cnd; + bool ep_configured; + bool acq_started; + size_t n_channels; + size_t active_channel; + bool plot_next_wave; +}; + +struct plotters { + FILE* gnuplot_h; + FILE* gnuplot_w; +}; + +static void print_stats(double t, size_t n_events, double rate) { + printf("\x1b[1K\rTime (s): %.1f\tEvents: %zu\tReadout rate (MB/s): %f", t, n_events, rate); + fflush(stdout); +} + +static void plot_histogram(FILE* gnuplot, size_t channel, struct histograms* h) { + char filename[64]; + snprintf(filename, ARRAY_SIZE(filename), HISTO_FILE_NAME, channel); + FILE* f_histo = fopen(filename, "w"); + if (f_histo == NULL) { + fprintf(stderr, "fopen failed"); + thrd_exit(EXIT_FAILURE); + } + uint32_t* hc = h->histogram[channel]; + for (size_t i = 0; i < h->n_allocated_bins; ++i) + fprintf(f_histo, "%"PRIu32"\n", hc[i]); + fclose(f_histo); + fprintf(gnuplot, "set title 'Histogram (channel %zu)'\n", channel); + fprintf(gnuplot, "plot '%s' with step\n", filename); + fflush(gnuplot); +} + +static const char* digital_probe_type(uint8_t type) { + switch (type) { + case 0: return "trigger"; + case 1: return "time_filter_armed"; + case 2: return "re_trigger_guard"; + case 3: return "energy_filter_baseline_freeze"; + case 7: return "event_pile_up"; + case 20: return "over_threshold"; + case 21: return "charge_ready"; + case 22: return "long_gate"; + case 24: return "short_gate"; + case 25: return "input_saturation"; + case 26: return "charge_over_range"; + case 27: return "negative_over_threshold"; + default: return "UNKNOWN"; + } +} + +static const char* analog_probe_type(uint8_t type) { + switch (type) { + case 0: return "adc_input"; + case 9: return "baseline"; + case 10: return "cfd"; + default: return "UNKNOWN"; + } +} + +static void plot_waveform(FILE* gnuplot, struct event* evt) { + FILE* f_wave = fopen(WAVE_FILE_NAME, "w"); + if (f_wave == NULL) { + fprintf(stderr, "fopen failed"); + thrd_exit(EXIT_FAILURE); + } + fprintf(f_wave, "'%s'\t'%s'\t'%s'\t'%s'\t'%s'\t'%s'\n", + analog_probe_type(evt->analog_probes_type[0]), + analog_probe_type(evt->analog_probes_type[1]), + digital_probe_type(evt->digital_probes_type[0]), + digital_probe_type(evt->digital_probes_type[1]), + digital_probe_type(evt->digital_probes_type[2]), + digital_probe_type(evt->digital_probes_type[3]) + ); + for (size_t i = 0; i < evt->n_samples; ++i) + fprintf(f_wave, "%"PRIi32"\t%"PRIi32"\t%"PRIu8"\t%"PRIu8"\t%"PRIu8"\t%"PRIu8"\n", + evt->analog_probes[0][i], + evt->analog_probes[1][i], + evt->digital_probes[0][i], + evt->digital_probes[1][i], + evt->digital_probes[2][i], + evt->digital_probes[3][i] + ); + fclose(f_wave); + fprintf(gnuplot, "set title 'Waveform (channel %"PRIu8", timestamp %.3f us)'\n", evt->channel, evt->timestamp_us); + fprintf(gnuplot, "plot '%s' using 1 with step", WAVE_FILE_NAME); + fprintf(gnuplot, ", '' using 2 with step"); + fprintf(gnuplot, ", '' using (1000*$3 - 1100) with step"); + fprintf(gnuplot, ", '' using (1000*$4 - 2200) with step"); + fprintf(gnuplot, ", '' using (1000*$5 - 3300) with step"); + fprintf(gnuplot, ", '' using (1000*$6 - 4400) with step\n"); + fflush(gnuplot); +} + +static void save_event(FILE* f_evt, struct event* evt) { + const bool save_event = f_evt != NULL; + if (save_event) + fprintf(f_evt, "%"PRIu8"\t%.3f\t%"PRIu32"\t%"PRIu32"\n", evt->channel, evt->timestamp_us, evt->energy, evt->energy_short); +} + +static void fill_histogram(struct event* evt, struct histograms* h) { + /* + * fill histogram + * flags_high_priority bits: + * 0 or 1: pileup + * 2 or 3: adc saturation + * 4: energy ovverrange + */ + + // save events without these flags + if ((evt->flags_high_priority & 0x1f) == 0) + ++h->histogram[evt->channel][evt->energy]; + + // if trapsat is set, fill histogram last bin + else if (evt->flags_high_priority & 0x10) + ++h->histogram[evt->channel][h->n_allocated_bins - 1]; +} + +static double counters_dt(struct counters* c, time_t t) { + return difftime(t, c->t_begin); +} + +static double counters_rate(struct counters* c, time_t t) { + return c->total_size / counters_dt(c, t) / (1024. * 1024.); // MB/s +} + +static void counters_increment(struct counters* c, size_t size) { + c->total_size += size; + ++c->n_events; +} + +static void counters_reset(struct counters* c, time_t t) { + c->total_size = 0; + c->n_events = 0; + c->t_begin = t; +} + +static void read_data_loop(struct plotters* plotters, FILE* f_evt, struct acq_data* acq_data, uint64_t ep_handle, struct event* evt, struct histograms* h) { + + struct counters total; + struct counters interval; + + counters_reset(&total, time(NULL)); + counters_reset(&interval, total.t_begin); + + for (;;) { + const time_t current_time = time(NULL); + if (counters_dt(&interval, current_time) >= 1.) { + // print stats + print_stats(counters_dt(&total, current_time), total.n_events, counters_rate(&interval, current_time)); + counters_reset(&interval, current_time); + // plot histograms + mtx_lock(&acq_data->mtx); + plot_histogram(plotters->gnuplot_h, acq_data->active_channel, h); + mtx_unlock(&acq_data->mtx); + } + + const int ret = CAEN_FELib_ReadData(ep_handle, 100, + &evt->channel, + &evt->timestamp, + &evt->fine_timestamp, + &evt->energy, + &evt->energy_short, + evt->analog_probes[0], + evt->analog_probes[1], + evt->digital_probes[0], + evt->digital_probes[1], + evt->digital_probes[2], + evt->digital_probes[3], + &evt->analog_probes_type[0], + &evt->analog_probes_type[1], + &evt->digital_probes_type[0], + &evt->digital_probes_type[1], + &evt->digital_probes_type[2], + &evt->digital_probes_type[3], + &evt->n_samples, + &evt->flags_low_priority, + &evt->flags_high_priority, + &evt->event_size + ); + switch (ret) { + case CAEN_FELib_Success: { + + evt->timestamp_us = evt->timestamp * .008; + + counters_increment(&total, evt->event_size); + counters_increment(&interval, evt->event_size); + + fill_histogram(evt, h); + save_event(f_evt, evt); + + const bool has_waveform = evt->n_samples > 0; + + if (has_waveform) { + mtx_lock(&acq_data->mtx); + if (acq_data->plot_next_wave) { + acq_data->plot_next_wave = false; + plot_waveform(plotters->gnuplot_w, evt); + } + mtx_unlock(&acq_data->mtx); + } + + break; + } + case CAEN_FELib_Timeout: + break; + case CAEN_FELib_Stop: + printf("\nStop received.\n"); + return; + default: + print_last_error(); + break; + } + } +} + +static struct event* allocate_event(size_t n_samples) { + struct event* evt = malloc(sizeof(*evt)); + if (evt == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->n_allocated_samples = n_samples; + evt->n_samples = 0; + for (size_t i = 0; i < ARRAY_SIZE(evt->analog_probes); ++i) { + evt->analog_probes[i] = malloc(evt->n_allocated_samples * sizeof(*evt->analog_probes[i])); + if (evt->analog_probes[i] == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + } + for (size_t i = 0; i < ARRAY_SIZE(evt->digital_probes); ++i) { + evt->digital_probes[i] = malloc(evt->n_allocated_samples * sizeof(*evt->digital_probes[i])); + if (evt->digital_probes[i] == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + } + return evt; +} + +static void free_event(struct event* evt) { + for (size_t i = 0; i < ARRAY_SIZE(evt->analog_probes); ++i) + free(evt->analog_probes[i]); + for (size_t i = 0; i < ARRAY_SIZE(evt->digital_probes); ++i) + free(evt->digital_probes[i]); + free(evt); +} + +static struct histograms* allocate_histograms(size_t n_channels) { + struct histograms* histograms = malloc(sizeof(*histograms)); + if (histograms == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + histograms->n_allocated_channels = n_channels; + histograms->n_allocated_bins = MAX_NUMBER_OF_BINS; + histograms->histogram = malloc(histograms->n_allocated_channels * sizeof(*histograms->histogram)); + if (histograms->histogram == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + for (size_t i = 0; i < histograms->n_allocated_channels; ++i) { + histograms->histogram[i] = calloc(histograms->n_allocated_bins, sizeof(*histograms->histogram[i])); + if (histograms->histogram[i] == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + } + return histograms; +} + +static void free_histograms(struct histograms* h) { + for (size_t i = 0; i < h->n_allocated_channels; ++i) + free(h->histogram[i]); + free(h->histogram); +} + +static struct plotters* open_plotters() { + struct plotters* plotters = malloc(sizeof(*plotters)); + if (plotters == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + plotters->gnuplot_h = _popen(GNUPLOT, "w"); + if (plotters->gnuplot_h == NULL) { + fprintf(stderr, "popen failed"); + thrd_exit(EXIT_FAILURE); + } + plotters->gnuplot_w = _popen(GNUPLOT, "w"); + if (plotters->gnuplot_w == NULL) { + fprintf(stderr, "popen failed"); + thrd_exit(EXIT_FAILURE); + } + fprintf(plotters->gnuplot_h, "set xlabel 'ADC channels'\n"); + fprintf(plotters->gnuplot_h, "set ylabel 'Counts'\n"); + fprintf(plotters->gnuplot_h, "set grid\nset mouse\n"); + fflush(plotters->gnuplot_h); + + fprintf(plotters->gnuplot_w, "set key autotitle columnheader\n"); + fprintf(plotters->gnuplot_w, "set xlabel 'Samples'\n"); + fprintf(plotters->gnuplot_w, "set ylabel 'ADC counts'\n"); + fprintf(plotters->gnuplot_w, "set grid\nset mouse\n"); + fflush(plotters->gnuplot_w); + + return plotters; +} + +static void close_plotters(struct plotters* plotters) { + _pclose(plotters->gnuplot_h); + _pclose(plotters->gnuplot_w); +} + +static int acq_thread(void* p) { + + int ret; + + struct acq_data* data = (struct acq_data*)p; + uint64_t ep_handle; + + ret = CAEN_FELib_GetHandle(data->dev_handle, "/endpoint/dpppsd", &ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = configure_endpoint(ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // allocate stuff + struct event *evt = allocate_event(MAX_NUMBER_OF_SAMPLES); + struct histograms* h = allocate_histograms(data->n_channels); + struct plotters* plt = open_plotters(); + + FILE* f_evt = NULL; + + if (EVT_FILE_ENABLED) { + f_evt = fopen(EVT_FILE_NAME, "w"); + if (f_evt == NULL) { + fprintf(stderr, "fopen failed"); + return EXIT_FAILURE; + } + } + + // signal main thread + mtx_lock(&data->mtx); + data->ep_configured = true; + mtx_unlock(&data->mtx); + cnd_signal(&data->cnd); + + // wait main thread + mtx_lock(&data->mtx); + while (!data->acq_started) + cnd_wait(&data->cnd, &data->mtx); + mtx_unlock(&data->mtx); + + // acquisition loop + read_data_loop(plt, f_evt, data, ep_handle, evt, h); + + // quit + if (f_evt != NULL) + fclose(f_evt); + close_plotters(plt); + free_event(evt); + free_histograms(h); + + return EXIT_SUCCESS; +} + +int main(int argc, char* argv[]) { + + printf("##########################################\n"); + printf("\tCAEN firmware DPP-PSD demo\n"); + printf("##########################################\n"); + + if (argc > 2) { + fputs("invalid arguments", stderr); + return EXIT_FAILURE; + } + + int ret; + + // select device + uint64_t dev_handle; + ret = connect_to_digitizer(&dev_handle, argc, argv); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = print_digitizer_details(dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + size_t n_channels; + ret = get_n_channels(dev_handle, &n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("Resetting...\t"); + + // reset + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/reset"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // start acquisition thread + struct acq_data data = { + .dev_handle = dev_handle, + .ep_configured = false, + .acq_started = false, + .n_channels = n_channels, + .active_channel = 0, + .plot_next_wave = false, + }; + mtx_init(&data.mtx, mtx_plain); + cnd_init(&data.cnd); + thrd_t thrd; + ret = thrd_create(&thrd, &acq_thread, &data); + if (ret != thrd_success) { + fprintf(stderr, "thrd_create failed"); + return EXIT_FAILURE; + } + + printf("Configuring...\t"); + + ret = configure_digitizer(dev_handle, n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // wait configuration on acquisition thread + mtx_lock(&data.mtx); + while (!data.ep_configured) + cnd_wait(&data.cnd, &data.mtx); + mtx_unlock(&data.mtx); + + printf("done.\n"); + + printf("Starting...\t"); + + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/armacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/swstartacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // notify start to acquisition thread + mtx_lock(&data.mtx); + data.acq_started = true; + mtx_unlock(&data.mtx); + cnd_signal(&data.cnd); + + printf("##########################################\n"); + printf("Commands supported:\n"); + printf("\t[%c]\tsend manual trigger\n", COMMAND_TRIGGER); + printf("\t[%c]\tstop acquisition\n", COMMAND_STOP); + printf("\t[%c]\tincrement channel\n", COMMAND_INCR_CH); + printf("\t[%c]\tdecrement channel\n", COMMAND_DECR_CH); + printf("\t[%c]\tplot next waveform\n", COMMAND_PLOT_WAVE); + printf("##########################################\n"); + + bool do_quit = false; + + do { + const int c = _getch(); + switch (c) { + case COMMAND_TRIGGER: { + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/sendswtrigger"); + if (ret != CAEN_FELib_Success) + print_last_error(); + break; + } + case COMMAND_STOP: { + do_quit = true; + break; + } + case COMMAND_INCR_CH: { + mtx_lock(&data.mtx); + ++data.active_channel; + if (data.active_channel == n_channels) + data.active_channel = 0; + mtx_unlock(&data.mtx); + break; + } + case COMMAND_DECR_CH: { + mtx_lock(&data.mtx); + if (data.active_channel == 0) + data.active_channel = n_channels; + --data.active_channel; + mtx_unlock(&data.mtx); + break; + } + case COMMAND_PLOT_WAVE: { + mtx_lock(&data.mtx); + data.plot_next_wave = true; + mtx_unlock(&data.mtx); + break; + } + case '\n': { + break; + } + default: { + fprintf(stderr, "unknown command [%c]", c); + break; + } + } + } while (!do_quit); + + printf("\nStopping...\t"); + + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/disarmacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // wait the end of the acquisition + // that is going to finish just after the last event + int thrd_ret; + ret = thrd_join(thrd, &thrd_ret); + if (ret != thrd_success || thrd_ret != EXIT_SUCCESS) { + fprintf(stderr, "thrd_join error.\tret %d\tthrd_ret %d\n", ret, thrd_ret); + return EXIT_FAILURE; + } + mtx_destroy(&data.mtx); + cnd_destroy(&data.cnd); + + ret = CAEN_FELib_Close(dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("\nBye!\n"); + + return EXIT_SUCCESS; +} diff --git a/demo/caen-felib-demo-dpp-zle/Makefile b/demo/caen-felib-demo-dpp-zle/Makefile new file mode 100644 index 0000000..7f4a824 --- /dev/null +++ b/demo/caen-felib-demo-dpp-zle/Makefile @@ -0,0 +1,20 @@ +TARGET = caen-felib-demo-dpp-zle +CFLAGS = -std=gnu11 -O2 -g -Wall -pthread +LDFLAGS = -pthread +LDLIBS = -lpthread -lCAEN_FELib + +.PHONY: default all clean + +default: $(TARGET) +all: default + +OBJECTS = main.o + +.PRECIOUS: $(TARGET) $(OBJECTS) + +$(TARGET): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $@ + +clean: + -rm -f *.o + -rm -f $(TARGET) diff --git a/demo/caen-felib-demo-dpp-zle/c11threads.h b/demo/caen-felib-demo-dpp-zle/c11threads.h new file mode 100644 index 0000000..cccf430 --- /dev/null +++ b/demo/caen-felib-demo-dpp-zle/c11threads.h @@ -0,0 +1,533 @@ +/* +c11threads + +Authors: + John Tsiombikas - original POSIX threads wrapper + Oliver Old - win32 implementation + +I place this piece of code in the public domain. Feel free to use as you see +fit. I'd appreciate it if you keep my name at the top of the code somewhere, but +whatever. + +Main project site: https://github.com/jtsiomb/c11threads +*/ +#ifndef C11THREADS_H_ +#define C11THREADS_H_ + +/* If you wish to use this with pthread-win32 (i.e. use the POSIX threads wrapper + * instead of the native win32 API implementation of C11 threads), then just + * define C11THREADS_PTHREAD_WIN32 before including this header file. + */ +#if defined(_WIN32) && !defined(C11THREADS_PTHREAD_WIN32) +#define C11THREADS_WIN32 +#endif + +/* If your compiler does not support the inline keyword, or supports it with + * some different variation of prefix or suffix underscores, you can define + * C11THREADS_INLINE before including this header file. + */ +#ifndef C11THREADS_INLINE +/* C99 compilers will have inline */ +#if __STDC_VERSION__ >= 199901L +#define C11THREADS_INLINE inline +/* C++ has inline */ +#elif defined(__cplusplus) +#define C11THREADS_INLINE inline +/* MSVC has inline from VS 2015 but supports __inline in older versions */ +#elif defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define C11THREADS_INLINE inline +#else +#define C11THREADS_INLINE __inline +#endif +/* for every other case, just gamble on having __inline__, and let the user + * define C11THREADS_INLINE if it breaks + */ +#else +#define C11THREADS_INLINE __inline__ +#endif +#endif /* !defined C11THREADS_INLINE */ + +#include + +#ifndef TIME_UTC +#define TIME_UTC 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*thrd_start_t)(void*); +typedef void (*tss_dtor_t)(void*); + +enum { + mtx_plain = 0, + mtx_recursive = 1, + mtx_timed = 2, +}; + +enum { + thrd_success, + thrd_timedout, + thrd_busy, + thrd_error, + thrd_nomem +}; + +#ifndef C11THREADS_WIN32 +/* C11 threads over POSIX threads as thin static inline wrapper functions */ +#include +#include +#include +#include /* for sched_yield */ +#include + +#ifndef thread_local +#define thread_local _Thread_local +#endif + +#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT +#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS + +#ifdef __APPLE__ +/* Darwin doesn't implement timed mutexes currently */ +#define C11THREADS_NO_TIMED_MUTEX +#include +#ifndef __MAC_10_15 +#define C11THREADS_NO_TIMESPEC_GET +#endif +#elif __STDC_VERSION__ < 201112L +#define C11THREADS_NO_TIMESPEC_GET +#endif + +#ifdef C11THREADS_NO_TIMED_MUTEX +#define C11THREADS_TIMEDLOCK_POLL_INTERVAL 5000000 /* 5 ms */ +#endif + +/* types */ +typedef pthread_t thrd_t; +typedef pthread_mutex_t mtx_t; +typedef pthread_cond_t cnd_t; +typedef pthread_key_t tss_t; +typedef pthread_once_t once_flag; + +/* ---- thread management ---- */ + +static C11THREADS_INLINE int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + int res = pthread_create(thr, 0, (void*(*)(void*))func, arg); + if(res == 0) { + return thrd_success; + } + return res == ENOMEM ? thrd_nomem : thrd_error; +} + +static C11THREADS_INLINE void thrd_exit(int res) +{ + pthread_exit((void*)(intptr_t)res); +} + +static C11THREADS_INLINE int thrd_join(thrd_t thr, int *res) +{ + void *retval; + + if(pthread_join(thr, &retval) != 0) { + return thrd_error; + } + if(res) { + *res = (int)(intptr_t)retval; + } + return thrd_success; +} + +static C11THREADS_INLINE int thrd_detach(thrd_t thr) +{ + return pthread_detach(thr) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE thrd_t thrd_current(void) +{ + return pthread_self(); +} + +static C11THREADS_INLINE int thrd_equal(thrd_t a, thrd_t b) +{ + return pthread_equal(a, b); +} + +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out) +{ + if(nanosleep(ts_in, rem_out) < 0) { + if(errno == EINTR) return -1; + return -2; + } + return 0; +} + +static C11THREADS_INLINE void thrd_yield(void) +{ + sched_yield(); +} + +/* ---- mutexes ---- */ + +static C11THREADS_INLINE int mtx_init(mtx_t *mtx, int type) +{ + int res; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + + if(type & mtx_timed) { +#ifdef PTHREAD_MUTEX_TIMED_NP + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP); +#else + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); +#endif + } + if(type & mtx_recursive) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + + res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error; + pthread_mutexattr_destroy(&attr); + return res; +} + +static C11THREADS_INLINE void mtx_destroy(mtx_t *mtx) +{ + pthread_mutex_destroy(mtx); +} + +static C11THREADS_INLINE int mtx_lock(mtx_t *mtx) +{ + int res = pthread_mutex_lock(mtx); + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_trylock(mtx_t *mtx) +{ + int res = pthread_mutex_trylock(mtx); + if(res == EBUSY) { + return thrd_busy; + } + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + int res = 0; +#ifdef C11THREADS_NO_TIMED_MUTEX + /* fake a timedlock by polling trylock in a loop and waiting for a bit */ + struct timeval now; + struct timespec sleeptime; + + sleeptime.tv_sec = 0; + sleeptime.tv_nsec = C11THREADS_TIMEDLOCK_POLL_INTERVAL; + + while((res = pthread_mutex_trylock(mtx)) == EBUSY) { + gettimeofday(&now, NULL); + + if(now.tv_sec > ts->tv_sec || (now.tv_sec == ts->tv_sec && + (now.tv_usec * 1000) >= ts->tv_nsec)) { + return thrd_timedout; + } + + nanosleep(&sleeptime, NULL); + } +#else + if((res = pthread_mutex_timedlock(mtx, ts)) == ETIMEDOUT) { + return thrd_timedout; + } +#endif + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_unlock(mtx_t *mtx) +{ + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; +} + +/* ---- condition variables ---- */ + +static C11THREADS_INLINE int cnd_init(cnd_t *cond) +{ + return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void cnd_destroy(cnd_t *cond) +{ + pthread_cond_destroy(cond); +} + +static C11THREADS_INLINE int cnd_signal(cnd_t *cond) +{ + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_broadcast(cnd_t *cond) +{ + return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ + int res; + + if((res = pthread_cond_timedwait(cond, mtx, ts)) != 0) { + return res == ETIMEDOUT ? thrd_timedout : thrd_error; + } + return thrd_success; +} + +/* ---- thread-specific data ---- */ + +static C11THREADS_INLINE int tss_create(tss_t *key, tss_dtor_t dtor) +{ + return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void tss_delete(tss_t key) +{ + pthread_key_delete(key); +} + +static C11THREADS_INLINE int tss_set(tss_t key, void *val) +{ + return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void *tss_get(tss_t key) +{ + return pthread_getspecific(key); +} + +/* ---- misc ---- */ + +static C11THREADS_INLINE void call_once(once_flag *flag, void (*func)(void)) +{ + pthread_once(flag, func); +} + +#ifdef C11THREADS_NO_TIMESPEC_GET +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base) +{ + struct timeval tv; + + if(base != TIME_UTC) { + return 0; + } + + if(gettimeofday(&tv, 0) == -1) { + return 0; + } + + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + return base; +} +#endif + + +#else /* C11THREADS_WIN32 */ + +/* C11 threads implementation using native Win32 API calls (see c11threads_win32.c) */ + +#ifndef thread_local +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#else +#define thread_local _Thread_local +#endif +#endif + +#define ONCE_FLAG_INIT {0} +#define TSS_DTOR_ITERATIONS 4 + +#ifndef _UCRT +#define C11THREADS_NO_TIMESPEC_GET +#endif + +#ifdef _MSC_VER +#define C11THREADS_MSVC_NORETURN __declspec(noreturn) +#define C11THREADS_GNUC_NORETURN +#elif defined(__GNUC__) +#define C11THREADS_MSVC_NORETURN +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5) +#define C11THREADS_GNUC_NORETURN __attribute__((noreturn)) +#else +#define C11THREADS_GNUC_NORETURN +#endif +#else +#define C11THREADS_MSVC_NORETURN +#define C11THREADS_GNUC_NORETURN +#endif + +/* types */ +typedef unsigned long thrd_t; +typedef struct { + void *debug_info; + long lock_count; + long recursion_count; + void *owning_thread; + void *lock_semaphore; + void *spin_count; +} mtx_t; +typedef void *cnd_t; +typedef unsigned long tss_t; +typedef void *once_flag; +struct _c11threads_win32_timespec32_t { + long tv_sec; + long tv_nsec; +}; +struct _c11threads_win32_timespec64_t { +#ifdef _MSC_VER + __int64 tv_sec; +#else + long long tv_sec; +#endif + long tv_nsec; +}; +#if !defined(_UCRT) && !defined(_TIMESPEC_DEFINED) +#ifdef _USE_32BIT_TIME_T +struct timespec { + long tv_sec; + long tv_nsec; +}; +#elif !defined(_USE_32BIT_TIME_T) +struct timespec { + __int64 tv_sec; + long tv_nsec; +}; +#endif /* !defined(_USE_32BIT_TIME_T) */ +#endif /* !defined(_UCRT) && !defined(_TIMESPEC_DEFINED) */ + +/* Thread functions. */ + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); +/* Win32: Threads not created with thrd_create() need to call this to clean up TSS. */ +C11THREADS_MSVC_NORETURN void thrd_exit(int res) C11THREADS_GNUC_NORETURN; +int thrd_join(thrd_t thr, int *res); +int thrd_detach(thrd_t thr); +thrd_t thrd_current(void); +int thrd_equal(thrd_t a, thrd_t b); +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out); +void thrd_yield(void); + +/* Mutex functions. */ + +int mtx_init(mtx_t *mtx, int type); +void mtx_destroy(mtx_t *mtx); +int mtx_lock(mtx_t *mtx); +int mtx_trylock(mtx_t *mtx); +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); +int mtx_unlock(mtx_t *mtx); + +/* Condition variable functions. */ + +int cnd_init(cnd_t *cond); +void cnd_destroy(cnd_t *cond); +int cnd_signal(cnd_t *cond); +int cnd_broadcast(cnd_t *cond); +int cnd_wait(cnd_t *cond, mtx_t *mtx); +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); + +/* Thread-specific storage functions. */ + +int tss_create(tss_t *key, tss_dtor_t dtor); +void tss_delete(tss_t key); +int tss_set(tss_t key, void *val); +void *tss_get(tss_t key); + +/* One-time callable function. */ + +void call_once(once_flag *flag, void (*func)(void)); + +#ifdef C11THREADS_NO_TIMESPEC_GET +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base); +#endif + +/* Special Win32 functions. */ +/* Win32: Free resources associated with this library. */ +void c11threads_win32_destroy(void); +/* Win32: Register current Win32 thread in c11threads to allow for proper thrd_join(). */ +int c11threads_win32_thrd_self_register(void); +/* Win32: Register Win32 thread by ID in c11threads to allow for proper thrd_join(). */ +int c11threads_win32_thrd_register(unsigned long win32_thread_id); + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) /* Warning C4127: conditional expression is constant */ +#endif + +/* ---- thread management ---- */ + +int _c11threads_win32_thrd_sleep32(const struct _c11threads_win32_timespec32_t *ts_in, struct _c11threads_win32_timespec32_t *rem_out); +int _c11threads_win32_thrd_sleep64(const struct _c11threads_win32_timespec64_t *ts_in, struct _c11threads_win32_timespec64_t *rem_out); +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out) +{ + if (sizeof(ts_in->tv_sec) == 4) { + return _c11threads_win32_thrd_sleep32((const struct _c11threads_win32_timespec32_t*)ts_in, (struct _c11threads_win32_timespec32_t*)rem_out); + } else { + return _c11threads_win32_thrd_sleep64((const struct _c11threads_win32_timespec64_t*)ts_in, (struct _c11threads_win32_timespec64_t*)rem_out); + } +} + +/* ---- mutexes ---- */ + +int _c11threads_win32_mtx_timedlock32(mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts); +int _c11threads_win32_mtx_timedlock64(mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts); +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_mtx_timedlock32(mtx, (const struct _c11threads_win32_timespec32_t*)ts); + } else { + return _c11threads_win32_mtx_timedlock64(mtx, (const struct _c11threads_win32_timespec64_t*)ts); + } +} + +/* ---- condition variables ---- */ + +int _c11threads_win32_cnd_timedwait32(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts); +int _c11threads_win32_cnd_timedwait64(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts); +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_cnd_timedwait32(cond, mtx, (const struct _c11threads_win32_timespec32_t*)ts); + } else { + return _c11threads_win32_cnd_timedwait64(cond, mtx, (const struct _c11threads_win32_timespec64_t*)ts); + } +} + +/* ---- misc ---- */ + +#ifdef C11THREADS_NO_TIMESPEC_GET +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base); +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base); +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_timespec32_get((struct _c11threads_win32_timespec32_t*)ts, base); + } else { + return _c11threads_win32_timespec64_get((struct _c11threads_win32_timespec64_t*)ts, base); + } +} +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif /* C11THREADS_WIN32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* C11THREADS_H_ */ diff --git a/demo/caen-felib-demo-dpp-zle/c11threads_win32.c b/demo/caen-felib-demo-dpp-zle/c11threads_win32.c new file mode 100644 index 0000000..f8badec --- /dev/null +++ b/demo/caen-felib-demo-dpp-zle/c11threads_win32.c @@ -0,0 +1,1147 @@ +/* +Win32 implementation for c11threads. + +Authors: +John Tsiombikas +Oliver Old + +I place this piece of code in the public domain. Feel free to use as you see +fit. I'd appreciate it if you keep my name at the top of the code somewhere, but +whatever. + +Main project site: https://github.com/jtsiomb/c11threads +*/ + +#if defined(_WIN32) && !defined(C11THREADS_PTHREAD_WIN32) + +#ifdef _MSC_VER +/* Map debug malloc and free functions for debug builds. DO NOT CHANGE THE INCLUDE ORDER! */ +#define _CRTDBG_MAP_ALLOC +#include +#include +#endif + +#include "c11threads.h" + +#include +#include +#include + +#ifndef WINVER +#define WINVER 0x0400 /* Windows NT 4.0 */ +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT WINVER +#endif +#define WIN32_LEAN_AND_MEAN +#include + +#define _WIN32_WINNT_VISTA 0x0600 +#define THREAD_QUERY_LIMITED_INFORMATION (0x0800) + + +/* ---- library ---- */ + +typedef void (__stdcall *_c11threads_win32_InitializeConditionVariable_t)(void*); +typedef void (__stdcall *_c11threads_win32_WakeConditionVariable_t)(void*); +typedef void (__stdcall *_c11threads_win32_WakeAllConditionVariable_t)(void*); +typedef int (__stdcall *_c11threads_win32_SleepConditionVariableCS_t)(void*, PCRITICAL_SECTION, unsigned long); +typedef int (__stdcall *_c11threads_win32_InitOnceExecuteOnce_t)(void*, const void*, void*, void**); + +struct _c11threads_win32_thrd_entry_t { + struct _c11threads_win32_thrd_entry_t *next; + void *h; + thrd_t thrd; +}; + +struct _c11threads_win32_tss_dtor_entry_t { + struct _c11threads_win32_tss_dtor_entry_t *next; + tss_dtor_t dtor; + tss_t key; +}; + +static volatile long _c11threads_win32_initialized = 0; +static unsigned short _c11threads_win32_winver; +static _c11threads_win32_InitializeConditionVariable_t _c11threads_win32_InitializeConditionVariable; +static _c11threads_win32_WakeConditionVariable_t _c11threads_win32_WakeConditionVariable; +static _c11threads_win32_WakeAllConditionVariable_t _c11threads_win32_WakeAllConditionVariable; +static _c11threads_win32_SleepConditionVariableCS_t _c11threads_win32_SleepConditionVariableCS; +static _c11threads_win32_InitOnceExecuteOnce_t _c11threads_win32_InitOnceExecuteOnce; +static CRITICAL_SECTION _c11threads_win32_thrd_list_critical_section; +static struct _c11threads_win32_thrd_entry_t *_c11threads_win32_thrd_list_head = NULL; +static CRITICAL_SECTION _c11threads_win32_tss_dtor_list_critical_section; +static struct _c11threads_win32_tss_dtor_entry_t *_c11threads_win32_tss_dtor_list_head = NULL; + +#ifdef _MSC_VER +#pragma warning(push) +/* Warning C4996: 'GetVersion': was declared deprecated */ +/* Warning C28125: The function 'InitializeCriticalSection' must be called from within a try/except block. */ +/* Warning C28159: Consider using 'IsWindows*' instead of 'GetVersion'. Reason: Deprecated. Use VerifyVersionInfo* or IsWindows* macros from VersionHelpers. */ +#pragma warning(disable: 4996 28125 28159) +#endif +static void _c11threads_win32_init(void) +{ + unsigned short os_version; + os_version = (unsigned short)GetVersion(); /* Keep in mind: Maximum version for unmanifested apps is Windows 8 (0x0602). */ + _c11threads_win32_winver = (os_version << 8) | (os_version >> 8); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + void *kernel32; + kernel32 = GetModuleHandleW(L"kernel32.dll"); + if (!kernel32) { + abort(); + } + _c11threads_win32_InitializeConditionVariable = (_c11threads_win32_InitializeConditionVariable_t)GetProcAddress(kernel32, "InitializeConditionVariable"); + if (!_c11threads_win32_InitializeConditionVariable) { + abort(); + } + _c11threads_win32_WakeConditionVariable = (_c11threads_win32_WakeConditionVariable_t)GetProcAddress(kernel32, "WakeConditionVariable"); + if (!_c11threads_win32_WakeConditionVariable) { + abort(); + } + _c11threads_win32_WakeAllConditionVariable = (_c11threads_win32_WakeAllConditionVariable_t)GetProcAddress(kernel32, "WakeAllConditionVariable"); + if (!_c11threads_win32_WakeAllConditionVariable) { + abort(); + } + _c11threads_win32_SleepConditionVariableCS = (_c11threads_win32_SleepConditionVariableCS_t)GetProcAddress(kernel32, "SleepConditionVariableCS"); + if (!_c11threads_win32_SleepConditionVariableCS) { + abort(); + } + _c11threads_win32_InitOnceExecuteOnce = (_c11threads_win32_InitOnceExecuteOnce_t)GetProcAddress(kernel32, "InitOnceExecuteOnce"); + if (!_c11threads_win32_InitOnceExecuteOnce) { + abort(); + } + } + InitializeCriticalSection(&_c11threads_win32_thrd_list_critical_section); + InitializeCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static void _c11threads_win32_ensure_initialized(void) +{ + if (InterlockedCompareExchange(&_c11threads_win32_initialized, 1, 0) == 0) { + _c11threads_win32_init(); + InterlockedExchange(&_c11threads_win32_initialized, 2); + } else { +#ifdef _MSC_VER +#pragma warning(suppress: 28112) /* Warning C28112: A variable (_c11threads_win32_initialized) which is accessed via an Interlocked function must always be accessed via an Interlocked function. */ +#endif + while (_c11threads_win32_initialized == 1) { + Sleep(0); + } + } +} + +void c11threads_win32_destroy(void) +{ + struct _c11threads_win32_thrd_entry_t *thrd_entry; + struct _c11threads_win32_thrd_entry_t *thrd_entry_temp; + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry; + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry_temp; + + if (_c11threads_win32_initialized) { + DeleteCriticalSection(&_c11threads_win32_thrd_list_critical_section); + DeleteCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + thrd_entry = _c11threads_win32_thrd_list_head; + while (thrd_entry) { + thrd_entry_temp = thrd_entry->next; + CloseHandle(thrd_entry->h); + free(thrd_entry); + thrd_entry = thrd_entry_temp; + } + + tss_dtor_entry = _c11threads_win32_tss_dtor_list_head; + while (tss_dtor_entry) { + tss_dtor_entry_temp = tss_dtor_entry->next; + TlsFree(tss_dtor_entry->key); + free(tss_dtor_entry); + tss_dtor_entry = tss_dtor_entry_temp; + } + + _c11threads_win32_initialized = 0; + _c11threads_win32_thrd_list_head = NULL; + _c11threads_win32_tss_dtor_list_head = NULL; + } +} + +/* ---- utilities ---- */ + +static int _c11threads_win32_util_is_timespec32_valid(const struct _c11threads_win32_timespec32_t *ts) +{ + return ts->tv_sec >= 0 && ts->tv_nsec >= 0 && ts->tv_nsec <= 999999999; +} + +static int _c11threads_win32_util_is_timespec64_valid(const struct _c11threads_win32_timespec64_t *ts) +{ + return ts->tv_sec >= 0 && ts->tv_nsec >= 0 && ts->tv_nsec <= 999999999; +} + +/* Precondition: 'ts' validated. */ +static __int64 _c11threads_win32_util_timespec32_to_file_time(const struct _c11threads_win32_timespec32_t *ts) +{ + unsigned __int64 sec_res; + unsigned __int64 nsec_res; + + sec_res = (unsigned __int64)ts->tv_sec * (unsigned __int64)10000000; + + /* Add another 100 ns if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 100UL + !!((unsigned long)ts->tv_nsec % 100UL); + + return sec_res + nsec_res; +} + +/* Precondition: 'ts' validated. */ +static __int64 _c11threads_win32_util_timespec64_to_file_time(const struct _c11threads_win32_timespec64_t *ts, size_t *periods) +{ + unsigned __int64 sec_res; + unsigned __int64 nsec_res; + unsigned __int64 res; + + *periods = (unsigned long)((unsigned __int64)ts->tv_sec / (unsigned __int64)922337203685); + sec_res = ((unsigned __int64)ts->tv_sec % (unsigned __int64)922337203685) * (unsigned __int64)10000000; + + /* Add another 100 ns if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 100UL + !!((unsigned long)ts->tv_nsec % 100UL); + + /* 64-bit time_t may cause overflow. */ + if (nsec_res > (unsigned __int64) - 1 - sec_res) { + ++*periods; + nsec_res -= (unsigned __int64) - 1 - sec_res; + sec_res = 0; + } + + res = sec_res + nsec_res; + + if (*periods && !res) { + --*periods; + return (__int64)9223372036850000000; + } + + return res; +} + +/* Precondition: 'ts' validated. */ +static int _c11threads_win32_util_timespec32_to_milliseconds(const struct _c11threads_win32_timespec32_t *ts, unsigned long *ms) +{ + unsigned long sec_res; + unsigned long nsec_res; + + /* Overflow. */ + if ((unsigned long)ts->tv_sec > (INFINITE - 1UL) / 1000UL) { + return 0; + } + + sec_res = (unsigned long)ts->tv_sec * 1000UL; + /* Add another millisecond if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 1000000UL + !!((unsigned long)ts->tv_nsec % 1000000UL); + + /* Overflow. */ + if (nsec_res > INFINITE - 1UL - sec_res) { + return 0; + } + + *ms = sec_res + nsec_res; + return 1; +} + +/* Precondition: 'ts' validated. */ +static int _c11threads_win32_util_timespec64_to_milliseconds(const struct _c11threads_win32_timespec64_t *ts, unsigned long *ms) +{ + unsigned long sec_res; + unsigned long nsec_res; + + /* Overflow. */ + if ((unsigned __int64)ts->tv_sec > (INFINITE - 1UL) / 1000UL) { + return 0; + } + + sec_res = (unsigned long)ts->tv_sec * 1000UL; + /* Add another millisecond if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 1000000UL + !!((unsigned long)ts->tv_nsec % 1000000UL); + + /* Overflow. */ + if (nsec_res > INFINITE - 1UL - sec_res) { + return 0; + } + + *ms = sec_res + nsec_res; + return 1; +} + +/* Precondition: 'current_time' and 'end_time' validated. */ +static unsigned long _c11threads_win32_util_timepoint_to_millisecond_timespan32(const struct _c11threads_win32_timespec32_t *current_time, const struct _c11threads_win32_timespec32_t *end_time, int *clamped) { + unsigned long wait_time; + struct _c11threads_win32_timespec32_t ts; + + *clamped = 0; + if (current_time->tv_sec > end_time->tv_sec || (current_time->tv_sec == end_time->tv_sec && current_time->tv_nsec >= end_time->tv_nsec)) { + wait_time = 0; + } else { + ts.tv_sec = end_time->tv_sec - current_time->tv_sec; + ts.tv_nsec = end_time->tv_nsec - current_time->tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000; + } + + if (!_c11threads_win32_util_timespec32_to_milliseconds(&ts, &wait_time)) { + /* Clamp wait_time. Pretend we've had a spurious wakeup if expired. */ + wait_time = INFINITE - 1; + *clamped = 1; + } + } + + return wait_time; +} + +/* Precondition: 'current_time' and 'end_time' validated. */ +static unsigned long _c11threads_win32_util_timepoint_to_millisecond_timespan64(const struct _c11threads_win32_timespec64_t *current_time, const struct _c11threads_win32_timespec64_t *end_time, int *clamped) { + unsigned long wait_time; + struct _c11threads_win32_timespec64_t ts; + + *clamped = 0; + if (current_time->tv_sec > end_time->tv_sec || (current_time->tv_sec == end_time->tv_sec && current_time->tv_nsec >= end_time->tv_nsec)) { + wait_time = 0; + } else { + ts.tv_sec = end_time->tv_sec - current_time->tv_sec; + ts.tv_nsec = end_time->tv_nsec - current_time->tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000; + } + + if (!_c11threads_win32_util_timespec64_to_milliseconds(&ts, &wait_time)) { + /* Clamp wait_time. Pretend we've had a spurious wakeup if expired. */ + wait_time = INFINITE - 1; + *clamped = 1; + } + } + + return wait_time; +} + +#if defined(C11THREADS_NO_TIMESPEC_GET) || !defined(_MSC_VER) +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base) +{ + FILETIME file_time; + ULARGE_INTEGER li; + + if (base != TIME_UTC) { + return 0; + } + + GetSystemTimeAsFileTime(&file_time); + + li.LowPart = file_time.dwLowDateTime; + li.HighPart = file_time.dwHighDateTime; + + /* Also subtract difference between FILETIME and UNIX time epoch. It's 369 years by the way. */ + ts->tv_sec = (long)(li.QuadPart / (unsigned __int64)10000000 - (unsigned __int64)11644473600); + ts->tv_nsec = (long)(li.QuadPart % (unsigned __int64)10000000) * 100; + + return base; +} + +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base) +{ + FILETIME file_time; + ULARGE_INTEGER li; + + if (base != TIME_UTC) { + return 0; + } + + GetSystemTimeAsFileTime(&file_time); + + li.LowPart = file_time.dwLowDateTime; + li.HighPart = file_time.dwHighDateTime; + + /* Also subtract difference between FILETIME and UNIX time epoch. It's 369 years by the way. */ + ts->tv_sec = li.QuadPart / (unsigned __int64)10000000 - (unsigned __int64)11644473600; + ts->tv_nsec = (long)(li.QuadPart % (unsigned __int64)10000000) * 100; + + return base; +} +#else +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base) +{ + return _timespec32_get((struct _timespec32*)ts, base); +} + +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base) +{ + return _timespec64_get((struct _timespec64*)ts, base); +} +#endif + +/* ---- thread management ---- */ + +static int _c11threads_win32_thrd_register(thrd_t thrd, HANDLE h) +{ + struct _c11threads_win32_thrd_entry_t *thread_entry; + + thread_entry = malloc(sizeof(*thread_entry)); + if (!thread_entry) { + return 0; + } + + thread_entry->thrd = thrd; + thread_entry->h = h; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + thread_entry->next = _c11threads_win32_thrd_list_head; + _c11threads_win32_thrd_list_head = thread_entry; + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + return 1; +} + +static void *_c11threads_win32_thrd_pop_entry(thrd_t thrd) +{ + void *h; + struct _c11threads_win32_thrd_entry_t *prev; + struct _c11threads_win32_thrd_entry_t *curr; + struct _c11threads_win32_thrd_entry_t *next; + + h = NULL; + prev = NULL; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + curr = _c11threads_win32_thrd_list_head; + while (curr) + { + if (curr->thrd == thrd) { + h = curr->h; + next = curr->next; + if (prev) { + prev->next = next; + } else { + _c11threads_win32_thrd_list_head = next; + } + break; + } + + prev = curr; + curr = curr->next; + } + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + free(curr); + return h; +} + +static void _c11threads_win32_thrd_run_tss_dtors(void) +{ + int ran_dtor; + size_t i; + struct _c11threads_win32_tss_dtor_entry_t *prev; + struct _c11threads_win32_tss_dtor_entry_t *curr; + struct _c11threads_win32_tss_dtor_entry_t *next; + void *val; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + ran_dtor = 1; + for (i = 0; i < TSS_DTOR_ITERATIONS && ran_dtor; ++i) { + ran_dtor = 0; + prev = NULL; + curr = _c11threads_win32_tss_dtor_list_head; + + while (curr) { + val = TlsGetValue(curr->key); + if (val) { + TlsSetValue(curr->key, NULL); + curr->dtor(val); + ran_dtor = 1; + } else if (GetLastError() != ERROR_SUCCESS) { + next = curr->next; + free(curr); + if (prev) { + prev->next = next; + } else { + _c11threads_win32_tss_dtor_list_head = next; + } + curr = next; + continue; + } + + curr = curr->next; + } + } + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); +} + +int c11threads_win32_thrd_self_register(void) +{ + unsigned long desired_access; + void *process; + void *thread; + + desired_access = SYNCHRONIZE | THREAD_QUERY_INFORMATION; + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + desired_access = SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION; + } + + process = GetCurrentProcess(); + thread = GetCurrentThread(); + if (!DuplicateHandle(process, thread, process, &thread, desired_access, 0, 0)) { + return thrd_error; + } + if (!_c11threads_win32_thrd_register(GetCurrentThreadId(), thread)) { + CloseHandle(thread); + return thrd_nomem; + } + return thrd_success; +} + +int c11threads_win32_thrd_register(unsigned long win32_thread_id) +{ + /* XXX temporary hack to make this build on MSVC6. Investigate further */ +#ifdef _PROCESSTHREADSAPI_H_ + unsigned long desired_access; + void *h; + + desired_access = SYNCHRONIZE | THREAD_QUERY_INFORMATION; + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + desired_access = SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION; + } + + h = OpenThread(desired_access, 0, win32_thread_id); + if (!h) { + return thrd_error; + } + if (!_c11threads_win32_thrd_register(win32_thread_id, h)) { + CloseHandle(h); + return thrd_nomem; + } +#endif + return thrd_success; +} + +struct _c11threads_win32_thrd_start_thunk_parameters_t { + thrd_start_t func; + void *arg; +}; + +static int __stdcall _c11threads_win32_thrd_start_thunk(struct _c11threads_win32_thrd_start_thunk_parameters_t *start_parameters) +{ + int res; + struct _c11threads_win32_thrd_start_thunk_parameters_t local_start_params; + local_start_params = *start_parameters; + free(start_parameters); + res = local_start_params.func(local_start_params.arg); + _c11threads_win32_thrd_run_tss_dtors(); + return res; +} + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + struct _c11threads_win32_thrd_start_thunk_parameters_t *thread_start_params; + struct _c11threads_win32_thrd_entry_t *thread_entry; + void *h; + + thread_start_params = malloc(sizeof(*thread_start_params)); + if (!thread_start_params) { + return thrd_nomem; + } + + thread_start_params->func = func; + thread_start_params->arg = arg; + + thread_entry = malloc(sizeof(*thread_entry)); + if (!thread_entry) { + free(thread_start_params); + return thrd_nomem; + } + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + h = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)_c11threads_win32_thrd_start_thunk, thread_start_params, 0, thr); + if (!h) { + unsigned long error; + error = GetLastError(); + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + free(thread_start_params); + free(thread_entry); + return error == ERROR_NOT_ENOUGH_MEMORY ? thrd_nomem : thrd_error; + } + thread_entry->next = _c11threads_win32_thrd_list_head; + thread_entry->h = h; + thread_entry->thrd = *thr; + _c11threads_win32_thrd_list_head = thread_entry; + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + return thrd_success; +} + +void thrd_exit(int res) +{ + _c11threads_win32_thrd_run_tss_dtors(); + ExitThread(res); +} + +int thrd_join(thrd_t thr, int *res) +{ + int ret; + void *h; + + ret = thrd_error; + h = _c11threads_win32_thrd_pop_entry(thr); + if (h) { + if (WaitForSingleObject(h, INFINITE) == WAIT_OBJECT_0 && (!res || GetExitCodeThread(h, (unsigned long*)res))) { + ret = thrd_success; + } + + CloseHandle(h); + } + + return ret; +} + +int thrd_detach(thrd_t thr) +{ + void *h; + h = _c11threads_win32_thrd_pop_entry(thr); + return h && CloseHandle(h) ? thrd_success : thrd_error; +} + +thrd_t thrd_current(void) +{ + return GetCurrentThreadId(); +} + +static int _c11threads_win32_sleep_common(__int64 file_time_in) +{ + void *timer; + unsigned long error; + LARGE_INTEGER due_time; + + assert(file_time_in >= 0); + + timer = CreateWaitableTimerW(NULL, 1, NULL); + if (!timer) { + error = GetLastError(); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + due_time.QuadPart = -file_time_in; + if (!SetWaitableTimer(timer, &due_time, 0, NULL, NULL, 0)) { + error = GetLastError(); + CloseHandle(timer); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) { + error = GetLastError(); + CloseHandle(timer); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + CloseHandle(timer); + return 0; /* Success. */ +} + +int _c11threads_win32_thrd_sleep32(const struct _c11threads_win32_timespec32_t *ts_in, struct _c11threads_win32_timespec32_t *rem_out) +{ + __int64 file_time; + int res; + + (void)rem_out; + + if (!_c11threads_win32_util_is_timespec32_valid(ts_in)) { + return -ERROR_INVALID_PARAMETER; + } + + file_time = _c11threads_win32_util_timespec32_to_file_time(ts_in); + if (file_time < 0) { + return -ERROR_INVALID_PARAMETER; + } + + res = _c11threads_win32_sleep_common(file_time); + + return res; +} + +int _c11threads_win32_thrd_sleep64(const struct _c11threads_win32_timespec64_t *ts_in, struct _c11threads_win32_timespec64_t *rem_out) +{ + __int64 file_time; + size_t periods; + int res; + + (void)rem_out; + + if (!_c11threads_win32_util_is_timespec64_valid(ts_in)) { + return -ERROR_INVALID_PARAMETER; + } + + file_time = _c11threads_win32_util_timespec64_to_file_time(ts_in, &periods); + if (file_time < 0) { + return -ERROR_INVALID_PARAMETER; + } + +restart_sleep: + res = _c11threads_win32_sleep_common(file_time); + + if (!res && periods) { + --periods; + file_time = (__int64)9223372036850000000; + goto restart_sleep; + } + + return res; +} + +void thrd_yield(void) +{ + SwitchToThread(); +} + +/* ---- mutexes ---- */ + +int mtx_init(mtx_t *mtx, int type) +{ + (void)type; +#ifdef _MSC_VER +#pragma warning(suppress: 28125) /* Warning C28125: The function 'InitializeCriticalSection' must be called from within a try/except block. */ +#endif + InitializeCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +void mtx_destroy(mtx_t *mtx) +{ + DeleteCriticalSection((PCRITICAL_SECTION)mtx); +} + +int mtx_lock(mtx_t *mtx) +{ + EnterCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +int mtx_trylock(mtx_t *mtx) +{ + return TryEnterCriticalSection((PCRITICAL_SECTION)mtx) ? thrd_success : thrd_busy; +} + +int _c11threads_win32_mtx_timedlock32(mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts) +{ + int success; + struct _c11threads_win32_timespec32_t ts_current; + + if (!_c11threads_win32_util_is_timespec32_valid(ts)) { + return thrd_error; + } + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + while (!success) { + if (!_c11threads_win32_timespec32_get(&ts_current, TIME_UTC)) { + return thrd_error; + } + + if (ts_current.tv_sec > ts->tv_sec || (ts_current.tv_sec == ts->tv_sec && ts_current.tv_nsec >= ts->tv_nsec)) { + return thrd_timedout; + } + + Sleep(0); + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + } + + return thrd_success; +} + +int _c11threads_win32_mtx_timedlock64(mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts) +{ + int success; + struct _c11threads_win32_timespec64_t ts_current; + + if (!_c11threads_win32_util_is_timespec64_valid(ts)) { + return thrd_error; + } + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + while (!success) { + if (!_c11threads_win32_timespec64_get(&ts_current, TIME_UTC)) { + return thrd_error; + } + + if (ts_current.tv_sec > ts->tv_sec || (ts_current.tv_sec == ts->tv_sec && ts_current.tv_nsec >= ts->tv_nsec)) { + return thrd_timedout; + } + + Sleep(0); + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + } + + return thrd_success; +} + +int mtx_unlock(mtx_t *mtx) +{ + LeaveCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +/* ---- condition variables ---- */ + +struct _c11threads_win32_cnd_t { + void *mutex; + void *signal_sema; + void *broadcast_event; + size_t wait_count; +}; + +int cnd_init(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_InitializeConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + + cnd = malloc(sizeof(*cnd)); + if (!cnd) { + return thrd_nomem; + } + + cnd->mutex = CreateMutexW(NULL, 0, NULL); + if (cnd->mutex) { + cnd->signal_sema = CreateSemaphoreW(NULL, 0, 0x7fffffff, NULL); + if (cnd->signal_sema) { + cnd->broadcast_event = CreateEventW(NULL, 1, 0, NULL); + if (cnd->broadcast_event) { + cnd->wait_count = 0; + *cond = cnd; + return thrd_success; + } + CloseHandle(cnd->signal_sema); + } + CloseHandle(cnd->mutex); + } + + free(cnd); + return thrd_error; + } +} + +void cnd_destroy(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver < _WIN32_WINNT_VISTA) { + struct _c11threads_win32_cnd_t *cnd; + cnd = *cond; + assert(!cnd->wait_count); + CloseHandle(cnd->mutex); + CloseHandle(cnd->signal_sema); + CloseHandle(cnd->broadcast_event); + free(cnd); + } +} + +int cnd_signal(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_WakeConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + int success; + unsigned long wait_status; + + cnd = *cond; + + success = 0; + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_OBJECT_0) { + success = 1; + } else if (wait_status == WAIT_ABANDONED) { + abort(); + } + + if (success) { + if (cnd->wait_count) { + success = ReleaseSemaphore(cnd->signal_sema, 1, NULL) || GetLastError() == ERROR_TOO_MANY_POSTS; + } + if (!ReleaseMutex(cnd->mutex)) { + success = 0; + } + } + + return success ? thrd_success : thrd_error; + } +} + +int cnd_broadcast(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_WakeAllConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + int success; + unsigned long wait_status; + + cnd = *cond; + + success = 0; + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_OBJECT_0) { + success = 1; + } else if (wait_status == WAIT_ABANDONED) { + abort(); + } + + if (success) { + if (cnd->wait_count) { + success = SetEvent(cnd->broadcast_event); + } + if (!ReleaseMutex(cnd->mutex)) { + success = 0; + } + } + + return success ? thrd_success : thrd_error; + } +} + +static int _c11threads_win32_cnd_wait_common(cnd_t *cond, mtx_t *mtx, unsigned long wait_time, int clamped) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + if (_c11threads_win32_SleepConditionVariableCS(cond, (PCRITICAL_SECTION)mtx, wait_time)) { + return thrd_success; + } + + if (GetLastError() == ERROR_TIMEOUT) { + return clamped ? thrd_success : thrd_timedout; + } + + return thrd_error; + } else { + struct _c11threads_win32_cnd_t *cnd; + unsigned long wait_status; + unsigned long wait_status_2; + int res; + + cnd = *cond; + + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_ABANDONED) { + abort(); + } else if (wait_status != WAIT_OBJECT_0) { + return thrd_error; + } + LeaveCriticalSection((PCRITICAL_SECTION)mtx); + ++cnd->wait_count; + if (!ReleaseMutex(cnd->mutex)) { + abort(); + } + + wait_status = WaitForMultipleObjects(2, &cnd->signal_sema /* and cnd->broadcast_event */, 0, wait_time); + + if (WaitForSingleObject(cnd->mutex, INFINITE) != WAIT_OBJECT_0) { + abort(); + } + --cnd->wait_count; + if (!cnd->wait_count) { + do { + wait_status_2 = WaitForSingleObject(cnd->signal_sema, 0); + } while (wait_status_2 == WAIT_OBJECT_0); + if (wait_status_2 != WAIT_TIMEOUT) { + abort(); + } + + if (!ResetEvent(cnd->broadcast_event)) { + abort(); + } + } + if (!ReleaseMutex(cnd->mutex)) { + abort(); + } + + res = thrd_success; + if (wait_status == WAIT_TIMEOUT) { + if (!clamped) { + res = thrd_timedout; + } + } else if (wait_status != WAIT_OBJECT_0 && wait_status != WAIT_OBJECT_0 + 1) { + res = thrd_error; + } + + EnterCriticalSection((PCRITICAL_SECTION)mtx); + return res; + } +} + +int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return _c11threads_win32_cnd_wait_common(cond, mtx, INFINITE, 0); +} + +int _c11threads_win32_cnd_timedwait32(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts) +{ + struct _c11threads_win32_timespec32_t current_time; + unsigned long wait_time; + int clamped; + + if (!_c11threads_win32_util_is_timespec32_valid(ts)) { + return thrd_error; + } + + if (!_c11threads_win32_timespec32_get(¤t_time, TIME_UTC)) { + return thrd_error; + } + + wait_time = _c11threads_win32_util_timepoint_to_millisecond_timespan32(¤t_time, ts, &clamped); + + return _c11threads_win32_cnd_wait_common(cond, mtx, wait_time, clamped); +} + +int _c11threads_win32_cnd_timedwait64(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts) +{ + struct _c11threads_win32_timespec64_t current_time; + unsigned long wait_time; + int clamped; + + if (!_c11threads_win32_util_is_timespec64_valid(ts)) { + return thrd_error; + } + + if (!_c11threads_win32_timespec64_get(¤t_time, TIME_UTC)) { + return thrd_error; + } + + wait_time = _c11threads_win32_util_timepoint_to_millisecond_timespan64(¤t_time, ts, &clamped); + + return _c11threads_win32_cnd_wait_common(cond, mtx, wait_time, clamped); +} + +/* ---- thread-specific data ---- */ + +static int _c11threads_win32_tss_register(tss_t key, tss_dtor_t dtor) { + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry; + + tss_dtor_entry = malloc(sizeof(*tss_dtor_entry)); + if (!tss_dtor_entry) { + return 0; + } + + tss_dtor_entry->key = key; + tss_dtor_entry->dtor = dtor; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + tss_dtor_entry->next = _c11threads_win32_tss_dtor_list_head; + _c11threads_win32_tss_dtor_list_head = tss_dtor_entry; + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + return 1; +} + +static void _c11threads_win32_tss_deregister(tss_t key) { + struct _c11threads_win32_tss_dtor_entry_t *prev; + struct _c11threads_win32_tss_dtor_entry_t *curr; + struct _c11threads_win32_tss_dtor_entry_t *next; + + prev = NULL; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + curr = _c11threads_win32_tss_dtor_list_head; + while (curr) + { + if (curr->key == key) { + next = curr->next; + if (prev) { + prev->next = next; + } else { + _c11threads_win32_tss_dtor_list_head = next; + } + break; + } + + prev = curr; + curr = curr->next; + } + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + free(curr); +} + +int tss_create(tss_t *key, tss_dtor_t dtor) +{ + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) { + return thrd_error; + } + if (dtor && !_c11threads_win32_tss_register(*key, dtor)) { + TlsFree(*key); + return thrd_error; + } + return thrd_success; +} + +void tss_delete(tss_t key) +{ + _c11threads_win32_tss_deregister(key); + TlsFree(key); +} + +int tss_set(tss_t key, void *val) +{ + return TlsSetValue(key, val) ? thrd_success : thrd_error; +} + +void *tss_get(tss_t key) +{ + return TlsGetValue(key); +} + +/* ---- misc ---- */ + +static int __stdcall _c11threads_win32_call_once_thunk(void *init_once, void (*func)(void), void **context) +{ + (void)init_once; + (void)context; + func(); + return 1; +} + +void call_once(once_flag *flag, void (*func)(void)) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { +#ifdef _MSC_VER +#pragma warning(push) +/* Warning C4054: 'type cast' : from function pointer 'int (__stdcall *)(void *,void (__cdecl *)(void),void **)' to data pointer 'const void *' */ +/* Warning C4054: 'type cast' : from function pointer 'void (__cdecl *)(void)' to data pointer 'void *' */ +#pragma warning(disable: 4054) +#endif + _c11threads_win32_InitOnceExecuteOnce((void*)flag, (const void*)_c11threads_win32_call_once_thunk, (void*)func, NULL); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } else { + if (InterlockedCompareExchange((long*)flag, 1, 0) == 0) { + func(); + InterlockedExchange((long*)flag, 2); + } else { + while (*(volatile long*)flag == 1) { + Sleep(0); + } + } + } +} + +#endif diff --git a/demo/caen-felib-demo-dpp-zle/caen-felib-demo-dpp-zle.vcxproj b/demo/caen-felib-demo-dpp-zle/caen-felib-demo-dpp-zle.vcxproj new file mode 100644 index 0000000..e2a001f --- /dev/null +++ b/demo/caen-felib-demo-dpp-zle/caen-felib-demo-dpp-zle.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {BEBE035B-E48D-4526-95EF-800B0C1A6728} + caenfelibdemodppzle + 10.0.16299.0 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-dpp-zle/caen-felib-demo-dpp-zle.vcxproj.filters b/demo/caen-felib-demo-dpp-zle/caen-felib-demo-dpp-zle.vcxproj.filters new file mode 100644 index 0000000..ef7db9a --- /dev/null +++ b/demo/caen-felib-demo-dpp-zle/caen-felib-demo-dpp-zle.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-dpp-zle/main.c b/demo/caen-felib-demo-dpp-zle/main.c new file mode 100644 index 0000000..0e4575a --- /dev/null +++ b/demo/caen-felib-demo-dpp-zle/main.c @@ -0,0 +1,738 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +* SPDX-License-Identifier: MIT-0 +* +***************************************************************************//*! +* +* \file main.c +* \brief CAEN Open FPGA Digitzers DPP-ZLE demo +* \author Giovanni Cerretani, Stefano Venditti +* +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +// windows or C11 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_THREADS__) +#include +#else +#include "c11threads.h" +#endif + +#include + +// Basic hardcoded configuration +#define COMMAND_TRIGGER 't' +#define COMMAND_STOP 'q' +#define COMMAND_PLOT_WAVE 'w' +#define MAX_NUMBER_OF_SAMPLES (1U << 10) +#define TIMEOUT_MS (100) +#define WAVE_FILE_NAME "Wave.txt" +#define WAVE_FILE_ENABLED false +#define EVT_FILE_NAME "EventInfo.txt" +#define EVT_FILE_ENABLED false +#define DATA_FORMAT " \ + [ \ + { \"name\" : \"TIMESTAMP\", \"type\" : \"U64\", \"dim\" : 0}, \ + { \"name\" : \"RECONSTRUCTED_WAVEFORM\", \"type\" : \"U16\", \"dim\" : 2}, \ + { \"name\" : \"RECONSTRUCTED_WAVEFORM_SIZE\", \"type\" : \"SIZE_T\", \"dim\" : 1}, \ + { \"name\" : \"EVENT_SIZE\", \"type\" : \"U32\", \"dim\" : 0} \ + ] \ +" +// Utilities +#define ARRAY_SIZE(X) (sizeof(X)/sizeof((X)[0])) + +#ifdef _WIN32 // Windows +#include +#define GNUPLOT "pgnuplot.exe" +#else // Linux +#include +#include +#define GNUPLOT "gnuplot" +#define _popen(command, type) popen(command, type) +#define _pclose(command) pclose(command) +// Linux replacement for non standard _getch +static int _getch() { + struct termios oldattr; + if (tcgetattr(STDIN_FILENO, &oldattr) == -1) perror(NULL); + struct termios newattr = oldattr; + newattr.c_lflag &= ~(ICANON | ECHO); + if (tcsetattr(STDIN_FILENO, TCSANOW, &newattr) == -1) perror(NULL); + const int ch = getchar(); + if (tcsetattr(STDIN_FILENO, TCSANOW, &oldattr) == -1) perror(NULL); + return ch; +} +#endif + +static unsigned long long value_to_ull(const char* value) { + char* value_end; + const unsigned long long ret = strtoull(value, &value_end, 0); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtoull error\n"); + return ret; +} + +static double value_to_d(const char* value) { + char* value_end; + const double ret = strtod(value, &value_end); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtod error\n"); + return ret; +} + +static int print_last_error(void) { + char msg[1024]; + int ec = CAEN_FELib_GetLastError(msg); + if (ec != CAEN_FELib_Success) { + fprintf(stderr, "%s failed\n", __func__); + return ec; + } + fprintf(stderr, "last error: %s\n", msg); + return ec; +} + +static int connect_to_digitizer(uint64_t* dev_handle, int argc, char* argv[]) { + const char* path; + char local_path[256]; + printf("device path: "); + if (argc == 2) { + path = argv[1]; + puts(path); + } else { + while (fgets(local_path, sizeof(local_path), stdin) == NULL); + local_path[strcspn(local_path, "\r\n")] = '\0'; // remove newline added by fgets + path = local_path; + } + return CAEN_FELib_Open(path, dev_handle); +} + +static int get_n_channels(uint64_t dev_handle, size_t* n_channels) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + *n_channels = (size_t)value_to_ull(value); + return ret; +} + +static int print_digitizer_details(uint64_t dev_handle) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/ModelName", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Model name:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/SerialNum", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Serial number:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_Nbit", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC bits:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Channels:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_SamplRate", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC rate:\t%f Msps\n", value_to_d(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/cupver", value); + if (ret != CAEN_FELib_Success) return ret; + printf("CUP version:\t%s\n", value); + return ret; +} + +static int configure_digitizer(uint64_t dev_handle, size_t n_channels) { + + int ret; + char value[256]; + char par_name[256]; + + // Channel settings + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChEnable", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "True"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/DCOffset", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "50"); + if (ret != CAEN_FELib_Success) return ret; + + // Global trigger configuration + ret = CAEN_FELib_SetValue(dev_handle, "/par/AcqTriggerSource", "SwTrg | TestPulse | ITLA"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ITLConnect", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "ITLA"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulsePeriod", "1000000000"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulseWidth", "16"); + if (ret != CAEN_FELib_Success) return ret; + + // ZLE-specific part + const unsigned int record_length = MAX_NUMBER_OF_SAMPLES; // in samples + snprintf(value, sizeof(value), "%u", record_length); + ret = CAEN_FELib_SetValue(dev_handle, "/par/RecordLengthS", value); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/TriggerThr", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "256"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ZLEChSupprThr", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "64"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChPreTriggerS", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "4"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChLookBackSamples", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "4"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChLookForwardSamples", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "4"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/EnZLESuppr", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "True"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/PulsePolarity", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "Positive"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/DefaultValueSource", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "Baseline"); + if (ret != CAEN_FELib_Success) return ret; + return ret; + +} + +static int configure_endpoint(uint64_t ep_handle) { + int ret; + // configure endpoint + uint64_t ep_folder_handle; + ret = CAEN_FELib_GetParentHandle(ep_handle, NULL, &ep_folder_handle); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(ep_folder_handle, "/par/activeendpoint", "dppzle"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetReadDataFormat(ep_handle, DATA_FORMAT); + if (ret != CAEN_FELib_Success) return ret; + return ret; +} + +struct counters { + size_t total_size; + size_t n_events; + time_t t_begin; +}; + +struct event { + uint64_t timestamp; + double timestamp_us; + uint32_t event_size; + uint16_t** waveform; + size_t* n_samples; + size_t* n_allocated_samples; + size_t n_channels; +}; + +struct acq_data { + mtx_t mtx; + cnd_t cnd; + uint64_t dev_handle; + bool ep_configured; + bool acq_started; + size_t n_channels; + bool plot_next_wave; +}; + +struct plotters { + FILE* gnuplot_w; +}; + +static void print_stats(double t, size_t n_events, double rate) { + printf("\x1b[1K\rTime (s): %.1f\tEvents: %zu\tReadout rate (MB/s): %f", t, n_events, rate); + fflush(stdout); +} + +static void print_rate(struct counters* c, double dt) { + const double rate = c->total_size / dt / (1024. * 1024.); + printf("Events:\t%zu\tReadout rate (MB/s):\t%f\n", c->n_events, rate); +} + +static void save_event(FILE* f_evt, FILE* f_wave, struct event* evt) { + + const bool save_event = f_evt != NULL; + const bool save_wave = f_wave != NULL; + const bool save_enabled = save_event || save_wave; + + if (save_enabled) { + char str[256]; + snprintf(str, sizeof(str), "ts: %.3f us\t\tevent_size: %"PRIu32"\t\tnum_samples: %zu\n", evt->timestamp_us, evt->event_size, evt->n_samples[0]); + if (save_event) { + fputs(str, f_evt); + } + if (save_wave) { + fputs(str, f_wave); + for (size_t i = 0; i < evt->n_channels; ++i) { + const size_t ch_size = evt->n_samples[i]; + if (ch_size > 0) { + fprintf(f_wave, "CH_%zu\n", i); + for (size_t s = 0; s < ch_size; ++s) + fprintf(f_wave, "%"PRIu16"\n", evt->waveform[i][s]); + } + } + } + } + +} + +static double counters_dt(struct counters* c, time_t t) { + return difftime(t, c->t_begin); +} + +static double counters_rate(struct counters* c, time_t t) { + return c->total_size / counters_dt(c, t) / (1024. * 1024.); // MB/s +} + +static void counters_increment(struct counters* c, size_t size) { + c->total_size += size; + ++c->n_events; +} + +static void counters_reset(struct counters* c, time_t t) { + c->total_size = 0; + c->n_events = 0; + c->t_begin = t; +} + +static void plot_waveform(FILE* gnuplot, struct event* evt) { + FILE* f_wave = fopen(WAVE_FILE_NAME, "w"); + if (f_wave == NULL) { + fprintf(stderr, "fopen failed"); + thrd_exit(EXIT_FAILURE); + } + // get max n_samples + size_t max_n_samples = 0; + for (size_t ch = 0; ch < evt->n_channels; ++ch) { + if (evt->n_samples[ch] > max_n_samples) + max_n_samples = evt->n_samples[ch]; + } + // title + for (size_t ch = 0; ch < evt->n_channels; ++ch) { + const bool last_ch = (ch == evt->n_channels - 1); + fprintf(f_wave, "CH%zu%c", ch, last_ch ? '\n' : '\t'); + } + // waveform + for (size_t i = 0; i < max_n_samples; ++i) { + for (size_t ch = 0; ch < evt->n_channels; ++ch) { + const bool last_ch = (ch == evt->n_channels - 1); + fprintf(f_wave, "%"PRIu16"%c", evt->waveform[ch][i], last_ch ? '\n' : '\t'); + } + } + fclose(f_wave); + fprintf(gnuplot, "set title 'Waveform (timestamp %.3f us)'\n", evt->timestamp_us); + for (size_t i = 0; i < evt->n_channels; ++i) { + const bool first_ch = (i == 0); + const bool last_ch = (i == evt->n_channels - 1); + if (first_ch) + fprintf(gnuplot, "plot '%s' using %zu with step", WAVE_FILE_NAME, i + 1); + else + fprintf(gnuplot, ", '' using %zu with step", i + 1); + if (last_ch) + fputc('\n', gnuplot); + } + fflush(gnuplot); +} + +static void read_data_loop(struct plotters* plotters, FILE* f_evt, FILE* f_wave, struct acq_data* acq_data, uint64_t ep_handle, struct event* evt) { + + struct counters total; + struct counters interval; + + bool printdata = false; + + counters_reset(&total, time(NULL)); + counters_reset(&interval, total.t_begin); + + for (;;) { + + const time_t current_time = time(NULL); + if (counters_dt(&interval, current_time) >= 1.) { + // print stats + print_stats(counters_dt(&total, current_time), total.n_events, counters_rate(&interval, current_time)); + counters_reset(&interval, current_time); + } + + const int ret = CAEN_FELib_ReadData(ep_handle, TIMEOUT_MS, + &evt->timestamp, + evt->waveform, + evt->n_samples, + &evt->event_size + ); + + switch (ret) { + case CAEN_FELib_Success: { + printdata = true; + counters_increment(&total, evt->event_size); + counters_increment(&interval, evt->event_size); + + evt->timestamp_us = evt->timestamp * .008; + + save_event(f_evt, f_wave, evt); + + mtx_lock(&acq_data->mtx); + if (acq_data->plot_next_wave) { + acq_data->plot_next_wave = false; + plot_waveform(plotters->gnuplot_w, evt); + } + mtx_unlock(&acq_data->mtx); + + break; + } + case CAEN_FELib_Timeout: + break; + case CAEN_FELib_Stop: + printf("Stop received. Run summary:\n"); + print_rate(&total, counters_dt(&total, current_time)); + return; + default: + print_last_error(); + break; + } + } +} + +static struct event* allocate_event(size_t n_channels, size_t n_samples) { + struct event* evt = malloc(sizeof(*evt)); + if (evt == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->n_channels = n_channels; + evt->n_samples = malloc(evt->n_channels * sizeof(*evt->n_samples)); + if (evt->n_samples == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->n_allocated_samples = malloc(evt->n_channels * sizeof(*evt->n_allocated_samples)); + if (evt->n_allocated_samples == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->waveform = malloc(evt->n_channels * sizeof(*evt->waveform)); + if (evt->waveform == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + for (size_t i = 0; i < evt->n_channels; ++i) { + evt->n_allocated_samples[i] = n_samples; + evt->waveform[i] = malloc(evt->n_allocated_samples[i] * sizeof(*evt->waveform[i])); + if (evt->waveform[i] == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + } + return evt; +} + +static void free_event(struct event* evt) { + for (size_t i = 0; i < evt->n_channels; ++i) + free(evt->waveform[i]); + free(evt->waveform); + free(evt->n_allocated_samples); + free(evt->n_samples); + free(evt); +} + +static struct plotters* open_plotters() { + struct plotters* plotters = malloc(sizeof(*plotters)); + if (plotters == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + plotters->gnuplot_w = _popen(GNUPLOT, "w"); + if (plotters->gnuplot_w == NULL) { + fprintf(stderr, "popen failed"); + thrd_exit(EXIT_FAILURE); + } + + fprintf(plotters->gnuplot_w, "set key autotitle columnheader\n"); + fprintf(plotters->gnuplot_w, "set xlabel 'Samples'\n"); + fprintf(plotters->gnuplot_w, "set ylabel 'ADC counts'\n"); + fprintf(plotters->gnuplot_w, "set grid\nset mouse\n"); + fprintf(plotters->gnuplot_w, "set key samplen 1 spacing 1\n"); + fflush(plotters->gnuplot_w); + + return plotters; +} + +static void close_plotters(struct plotters* plotters) { + _pclose(plotters->gnuplot_w); +} + +static int acq_thread(void* p) { + + int ret; + + struct acq_data* data = (struct acq_data*)p; + + uint64_t ep_handle; + ret = CAEN_FELib_GetHandle(data->dev_handle, "/endpoint/dppzle", &ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = configure_endpoint(ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + size_t n_channels; + ret = get_n_channels(data->dev_handle, &n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // allocate stuff + struct event* evt = allocate_event(n_channels, MAX_NUMBER_OF_SAMPLES); + struct plotters* plt = open_plotters(); + + FILE* f_evt = NULL; + FILE* f_wave = NULL; + + if (EVT_FILE_ENABLED) { + f_evt = fopen(EVT_FILE_NAME, "w"); + if (f_evt == NULL) { + fprintf(stderr, "fopen failed"); + return EXIT_FAILURE; + } + } + + if (WAVE_FILE_ENABLED) { + f_wave = fopen(WAVE_FILE_NAME, "w"); + if (f_wave == NULL) { + fprintf(stderr, "fopen failed"); + return EXIT_FAILURE; + } + } + + // signal main thread + mtx_lock(&data->mtx); + data->ep_configured = true; + mtx_unlock(&data->mtx); + cnd_signal(&data->cnd); + + // wait main thread + mtx_lock(&data->mtx); + while (!data->acq_started) + cnd_wait(&data->cnd, &data->mtx); + mtx_unlock(&data->mtx); + + // acquisition loop + read_data_loop(plt, f_evt, f_wave, data, ep_handle, evt); + + // quit + if (f_evt != NULL) + fclose(f_evt); + if (f_wave != NULL) + fclose(f_wave); + free_event(evt); + close_plotters(plt); + + return EXIT_SUCCESS; +} + +int main(int argc, char* argv[]) { + + printf("##########################################\n"); + printf("\tCAEN firmware ZLE demo\n"); + printf("##########################################\n"); + + if (argc > 2) { + fputs("invalid arguments", stderr); + return EXIT_FAILURE; + } + + int ret; + + // select device + uint64_t dev_handle; + ret = connect_to_digitizer(&dev_handle, argc, argv); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = print_digitizer_details(dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + size_t n_channels; + ret = get_n_channels(dev_handle, &n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("Resetting...\t"); + + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/reset"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // start acquisition thread + struct acq_data data = { + .dev_handle = dev_handle, + .ep_configured = false, + .acq_started = false, + .n_channels = n_channels, + .plot_next_wave = false, + }; + mtx_init(&data.mtx, mtx_plain); + cnd_init(&data.cnd); + thrd_t thrd; + ret = thrd_create(&thrd, &acq_thread, &data); + if (ret != thrd_success) { + fprintf(stderr, "thrd_create failed"); + return EXIT_FAILURE; + } + + printf("Configuring...\t"); + + ret = configure_digitizer(dev_handle, n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // wait configuration on acquisition thread + mtx_lock(&data.mtx); + while (!data.ep_configured) + cnd_wait(&data.cnd, &data.mtx); + mtx_unlock(&data.mtx); + + printf("done.\n"); + + printf("Starting...\t"); + + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/armacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/swstartacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // notify start to acquisition thread + mtx_lock(&data.mtx); + data.acq_started = true; + mtx_unlock(&data.mtx); + cnd_signal(&data.cnd); + + printf("##########################################\n"); + printf("Commands supported:\n"); + printf("\t[%c]\tsend manual trigger\n", COMMAND_TRIGGER); + printf("\t[%c]\tstop acquisition\n", COMMAND_STOP); + printf("\t[%c]\tplot next waveform\n", COMMAND_PLOT_WAVE); + printf("##########################################\n"); + + bool do_quit = false; + + do { + const int c = _getch(); + switch (c) { + + case COMMAND_TRIGGER: { + ret = CAEN_FELib_SendCommand(data.dev_handle, "/cmd/sendswtrigger"); + if (ret != CAEN_FELib_Success) + print_last_error(); + break; + } + case COMMAND_STOP: { + do_quit = true; + break; + } + case COMMAND_PLOT_WAVE: { + mtx_lock(&data.mtx); + data.plot_next_wave = true; + mtx_unlock(&data.mtx); + break; + } + case '\n': { + break; + } + default: { + fprintf(stderr, "unknown command [%c]", c); + break; + } + } + } while (!do_quit); + + printf("\nStopping...\t"); + + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/disarmacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // wait the end of the acquisition + // that is going to finish just after the last event + int thrd_ret; + ret = thrd_join(thrd, &thrd_ret); + if (ret != thrd_success || thrd_ret != EXIT_SUCCESS) { + fprintf(stderr, "thrd_join error.\tret %d\tthrd_ret %d\n", ret, thrd_ret); + return EXIT_FAILURE; + } + mtx_destroy(&data.mtx); + cnd_destroy(&data.cnd); + + ret = CAEN_FELib_Close(dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("Bye!\n"); + + return EXIT_SUCCESS; +} diff --git a/demo/caen-felib-demo-open-dpp/Makefile b/demo/caen-felib-demo-open-dpp/Makefile new file mode 100644 index 0000000..837a7a6 --- /dev/null +++ b/demo/caen-felib-demo-open-dpp/Makefile @@ -0,0 +1,20 @@ +TARGET = caen-felib-demo-open-dpp +CFLAGS = -std=gnu11 -O2 -g -Wall -pthread +LDFLAGS = -pthread +LDLIBS = -lpthread -lCAEN_FELib + +.PHONY: default all clean + +default: $(TARGET) +all: default + +OBJECTS = main.o + +.PRECIOUS: $(TARGET) $(OBJECTS) + +$(TARGET): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $@ + +clean: + -rm -f *.o + -rm -f $(TARGET) diff --git a/demo/caen-felib-demo-open-dpp/c11threads.h b/demo/caen-felib-demo-open-dpp/c11threads.h new file mode 100644 index 0000000..cccf430 --- /dev/null +++ b/demo/caen-felib-demo-open-dpp/c11threads.h @@ -0,0 +1,533 @@ +/* +c11threads + +Authors: + John Tsiombikas - original POSIX threads wrapper + Oliver Old - win32 implementation + +I place this piece of code in the public domain. Feel free to use as you see +fit. I'd appreciate it if you keep my name at the top of the code somewhere, but +whatever. + +Main project site: https://github.com/jtsiomb/c11threads +*/ +#ifndef C11THREADS_H_ +#define C11THREADS_H_ + +/* If you wish to use this with pthread-win32 (i.e. use the POSIX threads wrapper + * instead of the native win32 API implementation of C11 threads), then just + * define C11THREADS_PTHREAD_WIN32 before including this header file. + */ +#if defined(_WIN32) && !defined(C11THREADS_PTHREAD_WIN32) +#define C11THREADS_WIN32 +#endif + +/* If your compiler does not support the inline keyword, or supports it with + * some different variation of prefix or suffix underscores, you can define + * C11THREADS_INLINE before including this header file. + */ +#ifndef C11THREADS_INLINE +/* C99 compilers will have inline */ +#if __STDC_VERSION__ >= 199901L +#define C11THREADS_INLINE inline +/* C++ has inline */ +#elif defined(__cplusplus) +#define C11THREADS_INLINE inline +/* MSVC has inline from VS 2015 but supports __inline in older versions */ +#elif defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define C11THREADS_INLINE inline +#else +#define C11THREADS_INLINE __inline +#endif +/* for every other case, just gamble on having __inline__, and let the user + * define C11THREADS_INLINE if it breaks + */ +#else +#define C11THREADS_INLINE __inline__ +#endif +#endif /* !defined C11THREADS_INLINE */ + +#include + +#ifndef TIME_UTC +#define TIME_UTC 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*thrd_start_t)(void*); +typedef void (*tss_dtor_t)(void*); + +enum { + mtx_plain = 0, + mtx_recursive = 1, + mtx_timed = 2, +}; + +enum { + thrd_success, + thrd_timedout, + thrd_busy, + thrd_error, + thrd_nomem +}; + +#ifndef C11THREADS_WIN32 +/* C11 threads over POSIX threads as thin static inline wrapper functions */ +#include +#include +#include +#include /* for sched_yield */ +#include + +#ifndef thread_local +#define thread_local _Thread_local +#endif + +#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT +#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS + +#ifdef __APPLE__ +/* Darwin doesn't implement timed mutexes currently */ +#define C11THREADS_NO_TIMED_MUTEX +#include +#ifndef __MAC_10_15 +#define C11THREADS_NO_TIMESPEC_GET +#endif +#elif __STDC_VERSION__ < 201112L +#define C11THREADS_NO_TIMESPEC_GET +#endif + +#ifdef C11THREADS_NO_TIMED_MUTEX +#define C11THREADS_TIMEDLOCK_POLL_INTERVAL 5000000 /* 5 ms */ +#endif + +/* types */ +typedef pthread_t thrd_t; +typedef pthread_mutex_t mtx_t; +typedef pthread_cond_t cnd_t; +typedef pthread_key_t tss_t; +typedef pthread_once_t once_flag; + +/* ---- thread management ---- */ + +static C11THREADS_INLINE int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + int res = pthread_create(thr, 0, (void*(*)(void*))func, arg); + if(res == 0) { + return thrd_success; + } + return res == ENOMEM ? thrd_nomem : thrd_error; +} + +static C11THREADS_INLINE void thrd_exit(int res) +{ + pthread_exit((void*)(intptr_t)res); +} + +static C11THREADS_INLINE int thrd_join(thrd_t thr, int *res) +{ + void *retval; + + if(pthread_join(thr, &retval) != 0) { + return thrd_error; + } + if(res) { + *res = (int)(intptr_t)retval; + } + return thrd_success; +} + +static C11THREADS_INLINE int thrd_detach(thrd_t thr) +{ + return pthread_detach(thr) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE thrd_t thrd_current(void) +{ + return pthread_self(); +} + +static C11THREADS_INLINE int thrd_equal(thrd_t a, thrd_t b) +{ + return pthread_equal(a, b); +} + +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out) +{ + if(nanosleep(ts_in, rem_out) < 0) { + if(errno == EINTR) return -1; + return -2; + } + return 0; +} + +static C11THREADS_INLINE void thrd_yield(void) +{ + sched_yield(); +} + +/* ---- mutexes ---- */ + +static C11THREADS_INLINE int mtx_init(mtx_t *mtx, int type) +{ + int res; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + + if(type & mtx_timed) { +#ifdef PTHREAD_MUTEX_TIMED_NP + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP); +#else + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); +#endif + } + if(type & mtx_recursive) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + + res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error; + pthread_mutexattr_destroy(&attr); + return res; +} + +static C11THREADS_INLINE void mtx_destroy(mtx_t *mtx) +{ + pthread_mutex_destroy(mtx); +} + +static C11THREADS_INLINE int mtx_lock(mtx_t *mtx) +{ + int res = pthread_mutex_lock(mtx); + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_trylock(mtx_t *mtx) +{ + int res = pthread_mutex_trylock(mtx); + if(res == EBUSY) { + return thrd_busy; + } + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + int res = 0; +#ifdef C11THREADS_NO_TIMED_MUTEX + /* fake a timedlock by polling trylock in a loop and waiting for a bit */ + struct timeval now; + struct timespec sleeptime; + + sleeptime.tv_sec = 0; + sleeptime.tv_nsec = C11THREADS_TIMEDLOCK_POLL_INTERVAL; + + while((res = pthread_mutex_trylock(mtx)) == EBUSY) { + gettimeofday(&now, NULL); + + if(now.tv_sec > ts->tv_sec || (now.tv_sec == ts->tv_sec && + (now.tv_usec * 1000) >= ts->tv_nsec)) { + return thrd_timedout; + } + + nanosleep(&sleeptime, NULL); + } +#else + if((res = pthread_mutex_timedlock(mtx, ts)) == ETIMEDOUT) { + return thrd_timedout; + } +#endif + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_unlock(mtx_t *mtx) +{ + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; +} + +/* ---- condition variables ---- */ + +static C11THREADS_INLINE int cnd_init(cnd_t *cond) +{ + return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void cnd_destroy(cnd_t *cond) +{ + pthread_cond_destroy(cond); +} + +static C11THREADS_INLINE int cnd_signal(cnd_t *cond) +{ + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_broadcast(cnd_t *cond) +{ + return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ + int res; + + if((res = pthread_cond_timedwait(cond, mtx, ts)) != 0) { + return res == ETIMEDOUT ? thrd_timedout : thrd_error; + } + return thrd_success; +} + +/* ---- thread-specific data ---- */ + +static C11THREADS_INLINE int tss_create(tss_t *key, tss_dtor_t dtor) +{ + return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void tss_delete(tss_t key) +{ + pthread_key_delete(key); +} + +static C11THREADS_INLINE int tss_set(tss_t key, void *val) +{ + return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void *tss_get(tss_t key) +{ + return pthread_getspecific(key); +} + +/* ---- misc ---- */ + +static C11THREADS_INLINE void call_once(once_flag *flag, void (*func)(void)) +{ + pthread_once(flag, func); +} + +#ifdef C11THREADS_NO_TIMESPEC_GET +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base) +{ + struct timeval tv; + + if(base != TIME_UTC) { + return 0; + } + + if(gettimeofday(&tv, 0) == -1) { + return 0; + } + + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + return base; +} +#endif + + +#else /* C11THREADS_WIN32 */ + +/* C11 threads implementation using native Win32 API calls (see c11threads_win32.c) */ + +#ifndef thread_local +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#else +#define thread_local _Thread_local +#endif +#endif + +#define ONCE_FLAG_INIT {0} +#define TSS_DTOR_ITERATIONS 4 + +#ifndef _UCRT +#define C11THREADS_NO_TIMESPEC_GET +#endif + +#ifdef _MSC_VER +#define C11THREADS_MSVC_NORETURN __declspec(noreturn) +#define C11THREADS_GNUC_NORETURN +#elif defined(__GNUC__) +#define C11THREADS_MSVC_NORETURN +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5) +#define C11THREADS_GNUC_NORETURN __attribute__((noreturn)) +#else +#define C11THREADS_GNUC_NORETURN +#endif +#else +#define C11THREADS_MSVC_NORETURN +#define C11THREADS_GNUC_NORETURN +#endif + +/* types */ +typedef unsigned long thrd_t; +typedef struct { + void *debug_info; + long lock_count; + long recursion_count; + void *owning_thread; + void *lock_semaphore; + void *spin_count; +} mtx_t; +typedef void *cnd_t; +typedef unsigned long tss_t; +typedef void *once_flag; +struct _c11threads_win32_timespec32_t { + long tv_sec; + long tv_nsec; +}; +struct _c11threads_win32_timespec64_t { +#ifdef _MSC_VER + __int64 tv_sec; +#else + long long tv_sec; +#endif + long tv_nsec; +}; +#if !defined(_UCRT) && !defined(_TIMESPEC_DEFINED) +#ifdef _USE_32BIT_TIME_T +struct timespec { + long tv_sec; + long tv_nsec; +}; +#elif !defined(_USE_32BIT_TIME_T) +struct timespec { + __int64 tv_sec; + long tv_nsec; +}; +#endif /* !defined(_USE_32BIT_TIME_T) */ +#endif /* !defined(_UCRT) && !defined(_TIMESPEC_DEFINED) */ + +/* Thread functions. */ + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); +/* Win32: Threads not created with thrd_create() need to call this to clean up TSS. */ +C11THREADS_MSVC_NORETURN void thrd_exit(int res) C11THREADS_GNUC_NORETURN; +int thrd_join(thrd_t thr, int *res); +int thrd_detach(thrd_t thr); +thrd_t thrd_current(void); +int thrd_equal(thrd_t a, thrd_t b); +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out); +void thrd_yield(void); + +/* Mutex functions. */ + +int mtx_init(mtx_t *mtx, int type); +void mtx_destroy(mtx_t *mtx); +int mtx_lock(mtx_t *mtx); +int mtx_trylock(mtx_t *mtx); +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); +int mtx_unlock(mtx_t *mtx); + +/* Condition variable functions. */ + +int cnd_init(cnd_t *cond); +void cnd_destroy(cnd_t *cond); +int cnd_signal(cnd_t *cond); +int cnd_broadcast(cnd_t *cond); +int cnd_wait(cnd_t *cond, mtx_t *mtx); +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); + +/* Thread-specific storage functions. */ + +int tss_create(tss_t *key, tss_dtor_t dtor); +void tss_delete(tss_t key); +int tss_set(tss_t key, void *val); +void *tss_get(tss_t key); + +/* One-time callable function. */ + +void call_once(once_flag *flag, void (*func)(void)); + +#ifdef C11THREADS_NO_TIMESPEC_GET +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base); +#endif + +/* Special Win32 functions. */ +/* Win32: Free resources associated with this library. */ +void c11threads_win32_destroy(void); +/* Win32: Register current Win32 thread in c11threads to allow for proper thrd_join(). */ +int c11threads_win32_thrd_self_register(void); +/* Win32: Register Win32 thread by ID in c11threads to allow for proper thrd_join(). */ +int c11threads_win32_thrd_register(unsigned long win32_thread_id); + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) /* Warning C4127: conditional expression is constant */ +#endif + +/* ---- thread management ---- */ + +int _c11threads_win32_thrd_sleep32(const struct _c11threads_win32_timespec32_t *ts_in, struct _c11threads_win32_timespec32_t *rem_out); +int _c11threads_win32_thrd_sleep64(const struct _c11threads_win32_timespec64_t *ts_in, struct _c11threads_win32_timespec64_t *rem_out); +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out) +{ + if (sizeof(ts_in->tv_sec) == 4) { + return _c11threads_win32_thrd_sleep32((const struct _c11threads_win32_timespec32_t*)ts_in, (struct _c11threads_win32_timespec32_t*)rem_out); + } else { + return _c11threads_win32_thrd_sleep64((const struct _c11threads_win32_timespec64_t*)ts_in, (struct _c11threads_win32_timespec64_t*)rem_out); + } +} + +/* ---- mutexes ---- */ + +int _c11threads_win32_mtx_timedlock32(mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts); +int _c11threads_win32_mtx_timedlock64(mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts); +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_mtx_timedlock32(mtx, (const struct _c11threads_win32_timespec32_t*)ts); + } else { + return _c11threads_win32_mtx_timedlock64(mtx, (const struct _c11threads_win32_timespec64_t*)ts); + } +} + +/* ---- condition variables ---- */ + +int _c11threads_win32_cnd_timedwait32(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts); +int _c11threads_win32_cnd_timedwait64(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts); +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_cnd_timedwait32(cond, mtx, (const struct _c11threads_win32_timespec32_t*)ts); + } else { + return _c11threads_win32_cnd_timedwait64(cond, mtx, (const struct _c11threads_win32_timespec64_t*)ts); + } +} + +/* ---- misc ---- */ + +#ifdef C11THREADS_NO_TIMESPEC_GET +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base); +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base); +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_timespec32_get((struct _c11threads_win32_timespec32_t*)ts, base); + } else { + return _c11threads_win32_timespec64_get((struct _c11threads_win32_timespec64_t*)ts, base); + } +} +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif /* C11THREADS_WIN32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* C11THREADS_H_ */ diff --git a/demo/caen-felib-demo-open-dpp/c11threads_win32.c b/demo/caen-felib-demo-open-dpp/c11threads_win32.c new file mode 100644 index 0000000..f8badec --- /dev/null +++ b/demo/caen-felib-demo-open-dpp/c11threads_win32.c @@ -0,0 +1,1147 @@ +/* +Win32 implementation for c11threads. + +Authors: +John Tsiombikas +Oliver Old + +I place this piece of code in the public domain. Feel free to use as you see +fit. I'd appreciate it if you keep my name at the top of the code somewhere, but +whatever. + +Main project site: https://github.com/jtsiomb/c11threads +*/ + +#if defined(_WIN32) && !defined(C11THREADS_PTHREAD_WIN32) + +#ifdef _MSC_VER +/* Map debug malloc and free functions for debug builds. DO NOT CHANGE THE INCLUDE ORDER! */ +#define _CRTDBG_MAP_ALLOC +#include +#include +#endif + +#include "c11threads.h" + +#include +#include +#include + +#ifndef WINVER +#define WINVER 0x0400 /* Windows NT 4.0 */ +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT WINVER +#endif +#define WIN32_LEAN_AND_MEAN +#include + +#define _WIN32_WINNT_VISTA 0x0600 +#define THREAD_QUERY_LIMITED_INFORMATION (0x0800) + + +/* ---- library ---- */ + +typedef void (__stdcall *_c11threads_win32_InitializeConditionVariable_t)(void*); +typedef void (__stdcall *_c11threads_win32_WakeConditionVariable_t)(void*); +typedef void (__stdcall *_c11threads_win32_WakeAllConditionVariable_t)(void*); +typedef int (__stdcall *_c11threads_win32_SleepConditionVariableCS_t)(void*, PCRITICAL_SECTION, unsigned long); +typedef int (__stdcall *_c11threads_win32_InitOnceExecuteOnce_t)(void*, const void*, void*, void**); + +struct _c11threads_win32_thrd_entry_t { + struct _c11threads_win32_thrd_entry_t *next; + void *h; + thrd_t thrd; +}; + +struct _c11threads_win32_tss_dtor_entry_t { + struct _c11threads_win32_tss_dtor_entry_t *next; + tss_dtor_t dtor; + tss_t key; +}; + +static volatile long _c11threads_win32_initialized = 0; +static unsigned short _c11threads_win32_winver; +static _c11threads_win32_InitializeConditionVariable_t _c11threads_win32_InitializeConditionVariable; +static _c11threads_win32_WakeConditionVariable_t _c11threads_win32_WakeConditionVariable; +static _c11threads_win32_WakeAllConditionVariable_t _c11threads_win32_WakeAllConditionVariable; +static _c11threads_win32_SleepConditionVariableCS_t _c11threads_win32_SleepConditionVariableCS; +static _c11threads_win32_InitOnceExecuteOnce_t _c11threads_win32_InitOnceExecuteOnce; +static CRITICAL_SECTION _c11threads_win32_thrd_list_critical_section; +static struct _c11threads_win32_thrd_entry_t *_c11threads_win32_thrd_list_head = NULL; +static CRITICAL_SECTION _c11threads_win32_tss_dtor_list_critical_section; +static struct _c11threads_win32_tss_dtor_entry_t *_c11threads_win32_tss_dtor_list_head = NULL; + +#ifdef _MSC_VER +#pragma warning(push) +/* Warning C4996: 'GetVersion': was declared deprecated */ +/* Warning C28125: The function 'InitializeCriticalSection' must be called from within a try/except block. */ +/* Warning C28159: Consider using 'IsWindows*' instead of 'GetVersion'. Reason: Deprecated. Use VerifyVersionInfo* or IsWindows* macros from VersionHelpers. */ +#pragma warning(disable: 4996 28125 28159) +#endif +static void _c11threads_win32_init(void) +{ + unsigned short os_version; + os_version = (unsigned short)GetVersion(); /* Keep in mind: Maximum version for unmanifested apps is Windows 8 (0x0602). */ + _c11threads_win32_winver = (os_version << 8) | (os_version >> 8); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + void *kernel32; + kernel32 = GetModuleHandleW(L"kernel32.dll"); + if (!kernel32) { + abort(); + } + _c11threads_win32_InitializeConditionVariable = (_c11threads_win32_InitializeConditionVariable_t)GetProcAddress(kernel32, "InitializeConditionVariable"); + if (!_c11threads_win32_InitializeConditionVariable) { + abort(); + } + _c11threads_win32_WakeConditionVariable = (_c11threads_win32_WakeConditionVariable_t)GetProcAddress(kernel32, "WakeConditionVariable"); + if (!_c11threads_win32_WakeConditionVariable) { + abort(); + } + _c11threads_win32_WakeAllConditionVariable = (_c11threads_win32_WakeAllConditionVariable_t)GetProcAddress(kernel32, "WakeAllConditionVariable"); + if (!_c11threads_win32_WakeAllConditionVariable) { + abort(); + } + _c11threads_win32_SleepConditionVariableCS = (_c11threads_win32_SleepConditionVariableCS_t)GetProcAddress(kernel32, "SleepConditionVariableCS"); + if (!_c11threads_win32_SleepConditionVariableCS) { + abort(); + } + _c11threads_win32_InitOnceExecuteOnce = (_c11threads_win32_InitOnceExecuteOnce_t)GetProcAddress(kernel32, "InitOnceExecuteOnce"); + if (!_c11threads_win32_InitOnceExecuteOnce) { + abort(); + } + } + InitializeCriticalSection(&_c11threads_win32_thrd_list_critical_section); + InitializeCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static void _c11threads_win32_ensure_initialized(void) +{ + if (InterlockedCompareExchange(&_c11threads_win32_initialized, 1, 0) == 0) { + _c11threads_win32_init(); + InterlockedExchange(&_c11threads_win32_initialized, 2); + } else { +#ifdef _MSC_VER +#pragma warning(suppress: 28112) /* Warning C28112: A variable (_c11threads_win32_initialized) which is accessed via an Interlocked function must always be accessed via an Interlocked function. */ +#endif + while (_c11threads_win32_initialized == 1) { + Sleep(0); + } + } +} + +void c11threads_win32_destroy(void) +{ + struct _c11threads_win32_thrd_entry_t *thrd_entry; + struct _c11threads_win32_thrd_entry_t *thrd_entry_temp; + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry; + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry_temp; + + if (_c11threads_win32_initialized) { + DeleteCriticalSection(&_c11threads_win32_thrd_list_critical_section); + DeleteCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + thrd_entry = _c11threads_win32_thrd_list_head; + while (thrd_entry) { + thrd_entry_temp = thrd_entry->next; + CloseHandle(thrd_entry->h); + free(thrd_entry); + thrd_entry = thrd_entry_temp; + } + + tss_dtor_entry = _c11threads_win32_tss_dtor_list_head; + while (tss_dtor_entry) { + tss_dtor_entry_temp = tss_dtor_entry->next; + TlsFree(tss_dtor_entry->key); + free(tss_dtor_entry); + tss_dtor_entry = tss_dtor_entry_temp; + } + + _c11threads_win32_initialized = 0; + _c11threads_win32_thrd_list_head = NULL; + _c11threads_win32_tss_dtor_list_head = NULL; + } +} + +/* ---- utilities ---- */ + +static int _c11threads_win32_util_is_timespec32_valid(const struct _c11threads_win32_timespec32_t *ts) +{ + return ts->tv_sec >= 0 && ts->tv_nsec >= 0 && ts->tv_nsec <= 999999999; +} + +static int _c11threads_win32_util_is_timespec64_valid(const struct _c11threads_win32_timespec64_t *ts) +{ + return ts->tv_sec >= 0 && ts->tv_nsec >= 0 && ts->tv_nsec <= 999999999; +} + +/* Precondition: 'ts' validated. */ +static __int64 _c11threads_win32_util_timespec32_to_file_time(const struct _c11threads_win32_timespec32_t *ts) +{ + unsigned __int64 sec_res; + unsigned __int64 nsec_res; + + sec_res = (unsigned __int64)ts->tv_sec * (unsigned __int64)10000000; + + /* Add another 100 ns if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 100UL + !!((unsigned long)ts->tv_nsec % 100UL); + + return sec_res + nsec_res; +} + +/* Precondition: 'ts' validated. */ +static __int64 _c11threads_win32_util_timespec64_to_file_time(const struct _c11threads_win32_timespec64_t *ts, size_t *periods) +{ + unsigned __int64 sec_res; + unsigned __int64 nsec_res; + unsigned __int64 res; + + *periods = (unsigned long)((unsigned __int64)ts->tv_sec / (unsigned __int64)922337203685); + sec_res = ((unsigned __int64)ts->tv_sec % (unsigned __int64)922337203685) * (unsigned __int64)10000000; + + /* Add another 100 ns if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 100UL + !!((unsigned long)ts->tv_nsec % 100UL); + + /* 64-bit time_t may cause overflow. */ + if (nsec_res > (unsigned __int64) - 1 - sec_res) { + ++*periods; + nsec_res -= (unsigned __int64) - 1 - sec_res; + sec_res = 0; + } + + res = sec_res + nsec_res; + + if (*periods && !res) { + --*periods; + return (__int64)9223372036850000000; + } + + return res; +} + +/* Precondition: 'ts' validated. */ +static int _c11threads_win32_util_timespec32_to_milliseconds(const struct _c11threads_win32_timespec32_t *ts, unsigned long *ms) +{ + unsigned long sec_res; + unsigned long nsec_res; + + /* Overflow. */ + if ((unsigned long)ts->tv_sec > (INFINITE - 1UL) / 1000UL) { + return 0; + } + + sec_res = (unsigned long)ts->tv_sec * 1000UL; + /* Add another millisecond if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 1000000UL + !!((unsigned long)ts->tv_nsec % 1000000UL); + + /* Overflow. */ + if (nsec_res > INFINITE - 1UL - sec_res) { + return 0; + } + + *ms = sec_res + nsec_res; + return 1; +} + +/* Precondition: 'ts' validated. */ +static int _c11threads_win32_util_timespec64_to_milliseconds(const struct _c11threads_win32_timespec64_t *ts, unsigned long *ms) +{ + unsigned long sec_res; + unsigned long nsec_res; + + /* Overflow. */ + if ((unsigned __int64)ts->tv_sec > (INFINITE - 1UL) / 1000UL) { + return 0; + } + + sec_res = (unsigned long)ts->tv_sec * 1000UL; + /* Add another millisecond if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 1000000UL + !!((unsigned long)ts->tv_nsec % 1000000UL); + + /* Overflow. */ + if (nsec_res > INFINITE - 1UL - sec_res) { + return 0; + } + + *ms = sec_res + nsec_res; + return 1; +} + +/* Precondition: 'current_time' and 'end_time' validated. */ +static unsigned long _c11threads_win32_util_timepoint_to_millisecond_timespan32(const struct _c11threads_win32_timespec32_t *current_time, const struct _c11threads_win32_timespec32_t *end_time, int *clamped) { + unsigned long wait_time; + struct _c11threads_win32_timespec32_t ts; + + *clamped = 0; + if (current_time->tv_sec > end_time->tv_sec || (current_time->tv_sec == end_time->tv_sec && current_time->tv_nsec >= end_time->tv_nsec)) { + wait_time = 0; + } else { + ts.tv_sec = end_time->tv_sec - current_time->tv_sec; + ts.tv_nsec = end_time->tv_nsec - current_time->tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000; + } + + if (!_c11threads_win32_util_timespec32_to_milliseconds(&ts, &wait_time)) { + /* Clamp wait_time. Pretend we've had a spurious wakeup if expired. */ + wait_time = INFINITE - 1; + *clamped = 1; + } + } + + return wait_time; +} + +/* Precondition: 'current_time' and 'end_time' validated. */ +static unsigned long _c11threads_win32_util_timepoint_to_millisecond_timespan64(const struct _c11threads_win32_timespec64_t *current_time, const struct _c11threads_win32_timespec64_t *end_time, int *clamped) { + unsigned long wait_time; + struct _c11threads_win32_timespec64_t ts; + + *clamped = 0; + if (current_time->tv_sec > end_time->tv_sec || (current_time->tv_sec == end_time->tv_sec && current_time->tv_nsec >= end_time->tv_nsec)) { + wait_time = 0; + } else { + ts.tv_sec = end_time->tv_sec - current_time->tv_sec; + ts.tv_nsec = end_time->tv_nsec - current_time->tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000; + } + + if (!_c11threads_win32_util_timespec64_to_milliseconds(&ts, &wait_time)) { + /* Clamp wait_time. Pretend we've had a spurious wakeup if expired. */ + wait_time = INFINITE - 1; + *clamped = 1; + } + } + + return wait_time; +} + +#if defined(C11THREADS_NO_TIMESPEC_GET) || !defined(_MSC_VER) +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base) +{ + FILETIME file_time; + ULARGE_INTEGER li; + + if (base != TIME_UTC) { + return 0; + } + + GetSystemTimeAsFileTime(&file_time); + + li.LowPart = file_time.dwLowDateTime; + li.HighPart = file_time.dwHighDateTime; + + /* Also subtract difference between FILETIME and UNIX time epoch. It's 369 years by the way. */ + ts->tv_sec = (long)(li.QuadPart / (unsigned __int64)10000000 - (unsigned __int64)11644473600); + ts->tv_nsec = (long)(li.QuadPart % (unsigned __int64)10000000) * 100; + + return base; +} + +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base) +{ + FILETIME file_time; + ULARGE_INTEGER li; + + if (base != TIME_UTC) { + return 0; + } + + GetSystemTimeAsFileTime(&file_time); + + li.LowPart = file_time.dwLowDateTime; + li.HighPart = file_time.dwHighDateTime; + + /* Also subtract difference between FILETIME and UNIX time epoch. It's 369 years by the way. */ + ts->tv_sec = li.QuadPart / (unsigned __int64)10000000 - (unsigned __int64)11644473600; + ts->tv_nsec = (long)(li.QuadPart % (unsigned __int64)10000000) * 100; + + return base; +} +#else +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base) +{ + return _timespec32_get((struct _timespec32*)ts, base); +} + +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base) +{ + return _timespec64_get((struct _timespec64*)ts, base); +} +#endif + +/* ---- thread management ---- */ + +static int _c11threads_win32_thrd_register(thrd_t thrd, HANDLE h) +{ + struct _c11threads_win32_thrd_entry_t *thread_entry; + + thread_entry = malloc(sizeof(*thread_entry)); + if (!thread_entry) { + return 0; + } + + thread_entry->thrd = thrd; + thread_entry->h = h; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + thread_entry->next = _c11threads_win32_thrd_list_head; + _c11threads_win32_thrd_list_head = thread_entry; + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + return 1; +} + +static void *_c11threads_win32_thrd_pop_entry(thrd_t thrd) +{ + void *h; + struct _c11threads_win32_thrd_entry_t *prev; + struct _c11threads_win32_thrd_entry_t *curr; + struct _c11threads_win32_thrd_entry_t *next; + + h = NULL; + prev = NULL; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + curr = _c11threads_win32_thrd_list_head; + while (curr) + { + if (curr->thrd == thrd) { + h = curr->h; + next = curr->next; + if (prev) { + prev->next = next; + } else { + _c11threads_win32_thrd_list_head = next; + } + break; + } + + prev = curr; + curr = curr->next; + } + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + free(curr); + return h; +} + +static void _c11threads_win32_thrd_run_tss_dtors(void) +{ + int ran_dtor; + size_t i; + struct _c11threads_win32_tss_dtor_entry_t *prev; + struct _c11threads_win32_tss_dtor_entry_t *curr; + struct _c11threads_win32_tss_dtor_entry_t *next; + void *val; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + ran_dtor = 1; + for (i = 0; i < TSS_DTOR_ITERATIONS && ran_dtor; ++i) { + ran_dtor = 0; + prev = NULL; + curr = _c11threads_win32_tss_dtor_list_head; + + while (curr) { + val = TlsGetValue(curr->key); + if (val) { + TlsSetValue(curr->key, NULL); + curr->dtor(val); + ran_dtor = 1; + } else if (GetLastError() != ERROR_SUCCESS) { + next = curr->next; + free(curr); + if (prev) { + prev->next = next; + } else { + _c11threads_win32_tss_dtor_list_head = next; + } + curr = next; + continue; + } + + curr = curr->next; + } + } + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); +} + +int c11threads_win32_thrd_self_register(void) +{ + unsigned long desired_access; + void *process; + void *thread; + + desired_access = SYNCHRONIZE | THREAD_QUERY_INFORMATION; + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + desired_access = SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION; + } + + process = GetCurrentProcess(); + thread = GetCurrentThread(); + if (!DuplicateHandle(process, thread, process, &thread, desired_access, 0, 0)) { + return thrd_error; + } + if (!_c11threads_win32_thrd_register(GetCurrentThreadId(), thread)) { + CloseHandle(thread); + return thrd_nomem; + } + return thrd_success; +} + +int c11threads_win32_thrd_register(unsigned long win32_thread_id) +{ + /* XXX temporary hack to make this build on MSVC6. Investigate further */ +#ifdef _PROCESSTHREADSAPI_H_ + unsigned long desired_access; + void *h; + + desired_access = SYNCHRONIZE | THREAD_QUERY_INFORMATION; + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + desired_access = SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION; + } + + h = OpenThread(desired_access, 0, win32_thread_id); + if (!h) { + return thrd_error; + } + if (!_c11threads_win32_thrd_register(win32_thread_id, h)) { + CloseHandle(h); + return thrd_nomem; + } +#endif + return thrd_success; +} + +struct _c11threads_win32_thrd_start_thunk_parameters_t { + thrd_start_t func; + void *arg; +}; + +static int __stdcall _c11threads_win32_thrd_start_thunk(struct _c11threads_win32_thrd_start_thunk_parameters_t *start_parameters) +{ + int res; + struct _c11threads_win32_thrd_start_thunk_parameters_t local_start_params; + local_start_params = *start_parameters; + free(start_parameters); + res = local_start_params.func(local_start_params.arg); + _c11threads_win32_thrd_run_tss_dtors(); + return res; +} + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + struct _c11threads_win32_thrd_start_thunk_parameters_t *thread_start_params; + struct _c11threads_win32_thrd_entry_t *thread_entry; + void *h; + + thread_start_params = malloc(sizeof(*thread_start_params)); + if (!thread_start_params) { + return thrd_nomem; + } + + thread_start_params->func = func; + thread_start_params->arg = arg; + + thread_entry = malloc(sizeof(*thread_entry)); + if (!thread_entry) { + free(thread_start_params); + return thrd_nomem; + } + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + h = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)_c11threads_win32_thrd_start_thunk, thread_start_params, 0, thr); + if (!h) { + unsigned long error; + error = GetLastError(); + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + free(thread_start_params); + free(thread_entry); + return error == ERROR_NOT_ENOUGH_MEMORY ? thrd_nomem : thrd_error; + } + thread_entry->next = _c11threads_win32_thrd_list_head; + thread_entry->h = h; + thread_entry->thrd = *thr; + _c11threads_win32_thrd_list_head = thread_entry; + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + return thrd_success; +} + +void thrd_exit(int res) +{ + _c11threads_win32_thrd_run_tss_dtors(); + ExitThread(res); +} + +int thrd_join(thrd_t thr, int *res) +{ + int ret; + void *h; + + ret = thrd_error; + h = _c11threads_win32_thrd_pop_entry(thr); + if (h) { + if (WaitForSingleObject(h, INFINITE) == WAIT_OBJECT_0 && (!res || GetExitCodeThread(h, (unsigned long*)res))) { + ret = thrd_success; + } + + CloseHandle(h); + } + + return ret; +} + +int thrd_detach(thrd_t thr) +{ + void *h; + h = _c11threads_win32_thrd_pop_entry(thr); + return h && CloseHandle(h) ? thrd_success : thrd_error; +} + +thrd_t thrd_current(void) +{ + return GetCurrentThreadId(); +} + +static int _c11threads_win32_sleep_common(__int64 file_time_in) +{ + void *timer; + unsigned long error; + LARGE_INTEGER due_time; + + assert(file_time_in >= 0); + + timer = CreateWaitableTimerW(NULL, 1, NULL); + if (!timer) { + error = GetLastError(); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + due_time.QuadPart = -file_time_in; + if (!SetWaitableTimer(timer, &due_time, 0, NULL, NULL, 0)) { + error = GetLastError(); + CloseHandle(timer); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) { + error = GetLastError(); + CloseHandle(timer); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + CloseHandle(timer); + return 0; /* Success. */ +} + +int _c11threads_win32_thrd_sleep32(const struct _c11threads_win32_timespec32_t *ts_in, struct _c11threads_win32_timespec32_t *rem_out) +{ + __int64 file_time; + int res; + + (void)rem_out; + + if (!_c11threads_win32_util_is_timespec32_valid(ts_in)) { + return -ERROR_INVALID_PARAMETER; + } + + file_time = _c11threads_win32_util_timespec32_to_file_time(ts_in); + if (file_time < 0) { + return -ERROR_INVALID_PARAMETER; + } + + res = _c11threads_win32_sleep_common(file_time); + + return res; +} + +int _c11threads_win32_thrd_sleep64(const struct _c11threads_win32_timespec64_t *ts_in, struct _c11threads_win32_timespec64_t *rem_out) +{ + __int64 file_time; + size_t periods; + int res; + + (void)rem_out; + + if (!_c11threads_win32_util_is_timespec64_valid(ts_in)) { + return -ERROR_INVALID_PARAMETER; + } + + file_time = _c11threads_win32_util_timespec64_to_file_time(ts_in, &periods); + if (file_time < 0) { + return -ERROR_INVALID_PARAMETER; + } + +restart_sleep: + res = _c11threads_win32_sleep_common(file_time); + + if (!res && periods) { + --periods; + file_time = (__int64)9223372036850000000; + goto restart_sleep; + } + + return res; +} + +void thrd_yield(void) +{ + SwitchToThread(); +} + +/* ---- mutexes ---- */ + +int mtx_init(mtx_t *mtx, int type) +{ + (void)type; +#ifdef _MSC_VER +#pragma warning(suppress: 28125) /* Warning C28125: The function 'InitializeCriticalSection' must be called from within a try/except block. */ +#endif + InitializeCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +void mtx_destroy(mtx_t *mtx) +{ + DeleteCriticalSection((PCRITICAL_SECTION)mtx); +} + +int mtx_lock(mtx_t *mtx) +{ + EnterCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +int mtx_trylock(mtx_t *mtx) +{ + return TryEnterCriticalSection((PCRITICAL_SECTION)mtx) ? thrd_success : thrd_busy; +} + +int _c11threads_win32_mtx_timedlock32(mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts) +{ + int success; + struct _c11threads_win32_timespec32_t ts_current; + + if (!_c11threads_win32_util_is_timespec32_valid(ts)) { + return thrd_error; + } + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + while (!success) { + if (!_c11threads_win32_timespec32_get(&ts_current, TIME_UTC)) { + return thrd_error; + } + + if (ts_current.tv_sec > ts->tv_sec || (ts_current.tv_sec == ts->tv_sec && ts_current.tv_nsec >= ts->tv_nsec)) { + return thrd_timedout; + } + + Sleep(0); + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + } + + return thrd_success; +} + +int _c11threads_win32_mtx_timedlock64(mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts) +{ + int success; + struct _c11threads_win32_timespec64_t ts_current; + + if (!_c11threads_win32_util_is_timespec64_valid(ts)) { + return thrd_error; + } + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + while (!success) { + if (!_c11threads_win32_timespec64_get(&ts_current, TIME_UTC)) { + return thrd_error; + } + + if (ts_current.tv_sec > ts->tv_sec || (ts_current.tv_sec == ts->tv_sec && ts_current.tv_nsec >= ts->tv_nsec)) { + return thrd_timedout; + } + + Sleep(0); + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + } + + return thrd_success; +} + +int mtx_unlock(mtx_t *mtx) +{ + LeaveCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +/* ---- condition variables ---- */ + +struct _c11threads_win32_cnd_t { + void *mutex; + void *signal_sema; + void *broadcast_event; + size_t wait_count; +}; + +int cnd_init(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_InitializeConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + + cnd = malloc(sizeof(*cnd)); + if (!cnd) { + return thrd_nomem; + } + + cnd->mutex = CreateMutexW(NULL, 0, NULL); + if (cnd->mutex) { + cnd->signal_sema = CreateSemaphoreW(NULL, 0, 0x7fffffff, NULL); + if (cnd->signal_sema) { + cnd->broadcast_event = CreateEventW(NULL, 1, 0, NULL); + if (cnd->broadcast_event) { + cnd->wait_count = 0; + *cond = cnd; + return thrd_success; + } + CloseHandle(cnd->signal_sema); + } + CloseHandle(cnd->mutex); + } + + free(cnd); + return thrd_error; + } +} + +void cnd_destroy(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver < _WIN32_WINNT_VISTA) { + struct _c11threads_win32_cnd_t *cnd; + cnd = *cond; + assert(!cnd->wait_count); + CloseHandle(cnd->mutex); + CloseHandle(cnd->signal_sema); + CloseHandle(cnd->broadcast_event); + free(cnd); + } +} + +int cnd_signal(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_WakeConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + int success; + unsigned long wait_status; + + cnd = *cond; + + success = 0; + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_OBJECT_0) { + success = 1; + } else if (wait_status == WAIT_ABANDONED) { + abort(); + } + + if (success) { + if (cnd->wait_count) { + success = ReleaseSemaphore(cnd->signal_sema, 1, NULL) || GetLastError() == ERROR_TOO_MANY_POSTS; + } + if (!ReleaseMutex(cnd->mutex)) { + success = 0; + } + } + + return success ? thrd_success : thrd_error; + } +} + +int cnd_broadcast(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_WakeAllConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + int success; + unsigned long wait_status; + + cnd = *cond; + + success = 0; + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_OBJECT_0) { + success = 1; + } else if (wait_status == WAIT_ABANDONED) { + abort(); + } + + if (success) { + if (cnd->wait_count) { + success = SetEvent(cnd->broadcast_event); + } + if (!ReleaseMutex(cnd->mutex)) { + success = 0; + } + } + + return success ? thrd_success : thrd_error; + } +} + +static int _c11threads_win32_cnd_wait_common(cnd_t *cond, mtx_t *mtx, unsigned long wait_time, int clamped) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + if (_c11threads_win32_SleepConditionVariableCS(cond, (PCRITICAL_SECTION)mtx, wait_time)) { + return thrd_success; + } + + if (GetLastError() == ERROR_TIMEOUT) { + return clamped ? thrd_success : thrd_timedout; + } + + return thrd_error; + } else { + struct _c11threads_win32_cnd_t *cnd; + unsigned long wait_status; + unsigned long wait_status_2; + int res; + + cnd = *cond; + + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_ABANDONED) { + abort(); + } else if (wait_status != WAIT_OBJECT_0) { + return thrd_error; + } + LeaveCriticalSection((PCRITICAL_SECTION)mtx); + ++cnd->wait_count; + if (!ReleaseMutex(cnd->mutex)) { + abort(); + } + + wait_status = WaitForMultipleObjects(2, &cnd->signal_sema /* and cnd->broadcast_event */, 0, wait_time); + + if (WaitForSingleObject(cnd->mutex, INFINITE) != WAIT_OBJECT_0) { + abort(); + } + --cnd->wait_count; + if (!cnd->wait_count) { + do { + wait_status_2 = WaitForSingleObject(cnd->signal_sema, 0); + } while (wait_status_2 == WAIT_OBJECT_0); + if (wait_status_2 != WAIT_TIMEOUT) { + abort(); + } + + if (!ResetEvent(cnd->broadcast_event)) { + abort(); + } + } + if (!ReleaseMutex(cnd->mutex)) { + abort(); + } + + res = thrd_success; + if (wait_status == WAIT_TIMEOUT) { + if (!clamped) { + res = thrd_timedout; + } + } else if (wait_status != WAIT_OBJECT_0 && wait_status != WAIT_OBJECT_0 + 1) { + res = thrd_error; + } + + EnterCriticalSection((PCRITICAL_SECTION)mtx); + return res; + } +} + +int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return _c11threads_win32_cnd_wait_common(cond, mtx, INFINITE, 0); +} + +int _c11threads_win32_cnd_timedwait32(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts) +{ + struct _c11threads_win32_timespec32_t current_time; + unsigned long wait_time; + int clamped; + + if (!_c11threads_win32_util_is_timespec32_valid(ts)) { + return thrd_error; + } + + if (!_c11threads_win32_timespec32_get(¤t_time, TIME_UTC)) { + return thrd_error; + } + + wait_time = _c11threads_win32_util_timepoint_to_millisecond_timespan32(¤t_time, ts, &clamped); + + return _c11threads_win32_cnd_wait_common(cond, mtx, wait_time, clamped); +} + +int _c11threads_win32_cnd_timedwait64(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts) +{ + struct _c11threads_win32_timespec64_t current_time; + unsigned long wait_time; + int clamped; + + if (!_c11threads_win32_util_is_timespec64_valid(ts)) { + return thrd_error; + } + + if (!_c11threads_win32_timespec64_get(¤t_time, TIME_UTC)) { + return thrd_error; + } + + wait_time = _c11threads_win32_util_timepoint_to_millisecond_timespan64(¤t_time, ts, &clamped); + + return _c11threads_win32_cnd_wait_common(cond, mtx, wait_time, clamped); +} + +/* ---- thread-specific data ---- */ + +static int _c11threads_win32_tss_register(tss_t key, tss_dtor_t dtor) { + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry; + + tss_dtor_entry = malloc(sizeof(*tss_dtor_entry)); + if (!tss_dtor_entry) { + return 0; + } + + tss_dtor_entry->key = key; + tss_dtor_entry->dtor = dtor; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + tss_dtor_entry->next = _c11threads_win32_tss_dtor_list_head; + _c11threads_win32_tss_dtor_list_head = tss_dtor_entry; + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + return 1; +} + +static void _c11threads_win32_tss_deregister(tss_t key) { + struct _c11threads_win32_tss_dtor_entry_t *prev; + struct _c11threads_win32_tss_dtor_entry_t *curr; + struct _c11threads_win32_tss_dtor_entry_t *next; + + prev = NULL; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + curr = _c11threads_win32_tss_dtor_list_head; + while (curr) + { + if (curr->key == key) { + next = curr->next; + if (prev) { + prev->next = next; + } else { + _c11threads_win32_tss_dtor_list_head = next; + } + break; + } + + prev = curr; + curr = curr->next; + } + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + free(curr); +} + +int tss_create(tss_t *key, tss_dtor_t dtor) +{ + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) { + return thrd_error; + } + if (dtor && !_c11threads_win32_tss_register(*key, dtor)) { + TlsFree(*key); + return thrd_error; + } + return thrd_success; +} + +void tss_delete(tss_t key) +{ + _c11threads_win32_tss_deregister(key); + TlsFree(key); +} + +int tss_set(tss_t key, void *val) +{ + return TlsSetValue(key, val) ? thrd_success : thrd_error; +} + +void *tss_get(tss_t key) +{ + return TlsGetValue(key); +} + +/* ---- misc ---- */ + +static int __stdcall _c11threads_win32_call_once_thunk(void *init_once, void (*func)(void), void **context) +{ + (void)init_once; + (void)context; + func(); + return 1; +} + +void call_once(once_flag *flag, void (*func)(void)) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { +#ifdef _MSC_VER +#pragma warning(push) +/* Warning C4054: 'type cast' : from function pointer 'int (__stdcall *)(void *,void (__cdecl *)(void),void **)' to data pointer 'const void *' */ +/* Warning C4054: 'type cast' : from function pointer 'void (__cdecl *)(void)' to data pointer 'void *' */ +#pragma warning(disable: 4054) +#endif + _c11threads_win32_InitOnceExecuteOnce((void*)flag, (const void*)_c11threads_win32_call_once_thunk, (void*)func, NULL); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } else { + if (InterlockedCompareExchange((long*)flag, 1, 0) == 0) { + func(); + InterlockedExchange((long*)flag, 2); + } else { + while (*(volatile long*)flag == 1) { + Sleep(0); + } + } + } +} + +#endif diff --git a/demo/caen-felib-demo-open-dpp/caen-felib-demo-open-dpp.vcxproj b/demo/caen-felib-demo-open-dpp/caen-felib-demo-open-dpp.vcxproj new file mode 100644 index 0000000..fec5f48 --- /dev/null +++ b/demo/caen-felib-demo-open-dpp/caen-felib-demo-open-dpp.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {5478337c-0ccd-4d88-a80b-cef0eda7220a} + caenfelibdemoopendpp + 10.0.16299.0 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-open-dpp/caen-felib-demo-open-dpp.vcxproj.filters b/demo/caen-felib-demo-open-dpp/caen-felib-demo-open-dpp.vcxproj.filters new file mode 100644 index 0000000..ef7db9a --- /dev/null +++ b/demo/caen-felib-demo-open-dpp/caen-felib-demo-open-dpp.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-open-dpp/main.c b/demo/caen-felib-demo-open-dpp/main.c new file mode 100644 index 0000000..38d8836 --- /dev/null +++ b/demo/caen-felib-demo-open-dpp/main.c @@ -0,0 +1,588 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +* SPDX-License-Identifier: MIT-0 +* +***************************************************************************//*! +* +* \file main.c +* \brief CAEN Open FPGA Digitzers Open DPP demo +* \author Giovanni Cerretani +* +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +// windows or C11 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_THREADS__) +#include +#else +#include "c11threads.h" +#endif + +#include + +// Basic hardcoded configuration +#define COMMAND_TRIGGER 't' +#define COMMAND_STOP 'q' +#define MAX_NUMBER_OF_SAMPLES (4095 * 4) +#define TIMEOUT_MS (100) +#define WAVE_FILE_NAME "Wave.txt" +#define WAVE_FILE_ENABLED false +#define EVT_FILE_NAME "EventInfo.txt" +#define EVT_FILE_ENABLED false +#define DATA_FORMAT " \ + [ \ + { \"name\" : \"CHANNEL\", \"type\" : \"U8\" }, \ + { \"name\" : \"TIMESTAMP\", \"type\" : \"U64\" }, \ + { \"name\" : \"FINE_TIMESTAMP\", \"type\" : \"U16\" }, \ + { \"name\" : \"ENERGY\", \"type\" : \"U16\" }, \ + { \"name\" : \"WAVEFORM\", \"type\" : \"U16\", \"dim\" : 1 }, \ + { \"name\" : \"WAVEFORM_SIZE\", \"type\" : \"SIZE_T\" }, \ + { \"name\" : \"EVENT_SIZE\", \"type\" : \"SIZE_T\" } \ + ] \ +" + +// Utilities +#define ARRAY_SIZE(X) (sizeof(X)/sizeof((X)[0])) + +#ifdef _WIN32 // Windows +#include +#define GNUPLOT "pgnuplot.exe" +#else // Linux +#include +#include +#define GNUPLOT "gnuplot" +#define _popen(command, type) popen(command, type) +#define _pclose(command) pclose(command) +// Linux replacement for non standard _getch +static int _getch() { + struct termios oldattr; + if (tcgetattr(STDIN_FILENO, &oldattr) == -1) perror(NULL); + struct termios newattr = oldattr; + newattr.c_lflag &= ~(ICANON | ECHO); + if (tcsetattr(STDIN_FILENO, TCSANOW, &newattr) == -1) perror(NULL); + const int ch = getchar(); + if (tcsetattr(STDIN_FILENO, TCSANOW, &oldattr) == -1) perror(NULL); + return ch; +} +#endif + +static unsigned long long value_to_ull(const char* value) { + char* value_end; + const unsigned long long ret = strtoull(value, &value_end, 0); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtoull error\n"); + return ret; +} + +static double value_to_d(const char* value) { + char* value_end; + const double ret = strtod(value, &value_end); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtod error\n"); + return ret; +} + +static int print_last_error(void) { + char msg[1024]; + int ec = CAEN_FELib_GetLastError(msg); + if (ec != CAEN_FELib_Success) { + fprintf(stderr, "%s failed\n", __func__); + return ec; + } + fprintf(stderr, "last error: %s\n", msg); + return ec; +} + +static int connect_to_digitizer(uint64_t* dev_handle, int argc, char* argv[]) { + const char* path; + char local_path[256]; + printf("device path: "); + if (argc == 2) { + path = argv[1]; + puts(path); + } else { + while (fgets(local_path, sizeof(local_path), stdin) == NULL); + local_path[strcspn(local_path, "\r\n")] = '\0'; // remove newline added by fgets + path = local_path; + } + return CAEN_FELib_Open(path, dev_handle); +} + +static int get_n_channels(uint64_t dev_handle, size_t* n_channels) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + *n_channels = (size_t)value_to_ull(value); + return ret; +} + +static int print_digitizer_details(uint64_t dev_handle) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/ModelName", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Model name:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/SerialNum", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Serial number:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_Nbit", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC bits:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Channels:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_SamplRate", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC rate:\t%f Msps\n", value_to_d(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/cupver", value); + if (ret != CAEN_FELib_Success) return ret; + printf("CUP version:\t%s\n", value); + return ret; +} + +static int configure_digitizer(uint64_t dev_handle, size_t n_channels) { + + int ret; + char par_name[256]; + + // Channel enable + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChEnable", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "true"); + if (ret != CAEN_FELib_Success) return ret; + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/DCOffset", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "50"); + if (ret != CAEN_FELib_Success) return ret; + + // Global trigger configuration + ret = CAEN_FELib_SetValue(dev_handle, "/par/AcqTriggerSource", "SwTrg | TestPulse"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulsePeriod", "1000"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulseWidth", "16"); + if (ret != CAEN_FELib_Success) return ret; + + // set channel trigger source + for (uint32_t i = 0; i < 64; ++i) { + ret = CAEN_FELib_SetUserRegister(dev_handle, (uint32_t)(0x600U + 4U * i), 8); + if (ret != CAEN_FELib_Success) return ret; + } + + // set wavelength of channel 0 + ret = CAEN_FELib_SetUserRegister(dev_handle, 0x300, 1000); + if (ret != CAEN_FELib_Success) return ret; + + return ret; + +} + +static int configure_endpoint(uint64_t ep_handle) { + int ret; + // conigure endpoint + uint64_t ep_folder_handle; + ret = CAEN_FELib_GetParentHandle(ep_handle, NULL, &ep_folder_handle); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(ep_folder_handle, "/par/activeendpoint", "opendpp"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetReadDataFormat(ep_handle, DATA_FORMAT); + if (ret != CAEN_FELib_Success) return ret; + return ret; +} + +struct counters { + size_t total_size; + size_t n_events; + time_t t_begin; +}; + +struct event { + uint8_t channel; + uint64_t timestamp; + uint16_t fine_timestamp; + uint16_t energy; + size_t event_size; + uint16_t* waveform; + size_t n_allocated_samples; + size_t n_samples; +}; + +struct acq_data { + uint64_t dev_handle; + mtx_t mtx; + cnd_t cnd; + bool ep_configured; + bool acq_started; + size_t n_channels; +}; + +static void print_stats(double t, size_t n_events, double rate) { + printf("\x1b[1K\rTime (s): %.1f\tEvents: %zu\tReadout rate (MB/s): %f", t, n_events, rate); + fflush(stdout); +} + +static double counters_dt(struct counters* c, time_t t) { + return difftime(t, c->t_begin); +} + +static double counters_rate(struct counters* c, time_t t) { + return c->total_size / counters_dt(c, t) / (1024. * 1024.); // MB/s +} + +static void counters_increment(struct counters* c, size_t size) { + c->total_size += size; + ++c->n_events; +} + +static void counters_reset(struct counters* c, time_t t) { + c->total_size = 0; + c->n_events = 0; + c->t_begin = t; +} + +static void read_data_loop(FILE* f_evt, FILE* f_wave, uint64_t ep_handle, struct event* evt) { + + struct counters total; + struct counters interval; + + counters_reset(&total, time(NULL)); + counters_reset(&interval, total.t_begin); + + const bool save_event = f_evt != NULL; + const bool save_wave = f_wave != NULL; + const bool save_enabled = save_event || save_wave; + + for (;;) { + + const time_t current_time = time(NULL); + const double dt = counters_dt(&interval, current_time); + if (dt >= 1.) { + // print stats + print_stats(counters_dt(&total, current_time), total.n_events, counters_rate(&interval, current_time)); + counters_reset(&interval, current_time); + } + + const int ret = CAEN_FELib_ReadData(ep_handle, TIMEOUT_MS, + &evt->channel, + &evt->timestamp, + &evt->fine_timestamp, + &evt->energy, + evt->waveform, + &evt->n_samples, + &evt->event_size + ); + switch (ret) { + case CAEN_FELib_Success: { + + counters_increment(&total, evt->event_size); + counters_increment(&interval, evt->event_size); + + const double timestamp_us = evt->timestamp * .008; + + if (save_enabled) { + char str[256]; + snprintf(str, sizeof(str), "ts: %.3f us\t\tenergy: %"PRIu32"\t\tnum_samples: %zu\n", timestamp_us, evt->energy, evt->n_samples); + if (save_event) { + fputs(str, f_evt); + } + if (save_wave) { + fputs(str, f_wave); + for (size_t s = 0; s < evt->n_samples; ++s) + fprintf(f_wave, "%"PRIu16"\n", evt->waveform[s]); + } + } + + break; + } + case CAEN_FELib_Timeout: + break; + case CAEN_FELib_Stop: + printf("\nStop received.\n"); + return; + default: + print_last_error(); + break; + } + } +} + +static struct event* allocate_event(size_t n_samples) { + struct event* evt = malloc(sizeof(*evt)); + if (evt == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->n_allocated_samples = n_samples; + evt->n_samples = 0; + evt->waveform = malloc(evt->n_allocated_samples * sizeof(*evt->waveform)); + if (evt->waveform == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + return evt; +} + +static void free_event(struct event* evt) { + free(evt->waveform); + free(evt); +} + +static int acq_thread(void* p) { + + int ret; + + struct acq_data* data = (struct acq_data*)p; + uint64_t ep_handle; + + ret = CAEN_FELib_GetHandle(data->dev_handle, "/endpoint/opendpp", &ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = configure_endpoint(ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // allocate stuff + struct event* evt = allocate_event(MAX_NUMBER_OF_SAMPLES); + + FILE* f_evt = NULL; + FILE* f_wave = NULL; + + if (EVT_FILE_ENABLED) { + f_evt = fopen(EVT_FILE_NAME, "w"); + if (f_evt == NULL) { + fprintf(stderr, "fopen failed"); + return EXIT_FAILURE; + } + } + + if (WAVE_FILE_ENABLED) { + f_wave = fopen(WAVE_FILE_NAME, "w"); + if (f_wave == NULL) { + fprintf(stderr, "fopen failed"); + return EXIT_FAILURE; + } + } + + // signal main thread + mtx_lock(&data->mtx); + data->ep_configured = true; + mtx_unlock(&data->mtx); + cnd_signal(&data->cnd); + + // wait main thread + mtx_lock(&data->mtx); + while (!data->acq_started) + cnd_wait(&data->cnd, &data->mtx); + mtx_unlock(&data->mtx); + + // acquisition loop + read_data_loop(f_evt, f_wave, ep_handle, evt); + + // quit + if (f_evt != NULL) + fclose(f_evt); + + if (f_wave != NULL) + fclose(f_wave); + + free_event(evt); + + return EXIT_SUCCESS; +} + +int main(int argc, char* argv[]) { + + int ret; + + uint64_t dev_handle; + + printf("##########################################\n"); + printf("\tCAEN firmware Open DPP demo\n"); + printf("##########################################\n"); + + if (argc > 2) { + fputs("invalid arguments", stderr); + return EXIT_FAILURE; + } + + // select device + ret = connect_to_digitizer(&dev_handle, argc, argv); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = print_digitizer_details(dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + size_t n_channels; + ret = get_n_channels(dev_handle, &n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("Resetting...\t"); + + // reset + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/reset"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // start acquisition thread + struct acq_data data = { + .dev_handle = dev_handle, + .ep_configured = false, + .acq_started = false, + .n_channels = n_channels, + }; + mtx_init(&data.mtx, mtx_plain); + cnd_init(&data.cnd); + thrd_t thrd; + ret = thrd_create(&thrd, &acq_thread, &data); + if (ret != thrd_success) { + fprintf(stderr, "thrd_create failed"); + return EXIT_FAILURE; + } + + printf("Configuring...\t"); + + ret = configure_digitizer(dev_handle, n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // wait configuration on acquisition thread + mtx_lock(&data.mtx); + while (!data.ep_configured) + cnd_wait(&data.cnd, &data.mtx); + mtx_unlock(&data.mtx); + + printf("done.\n"); + + printf("Starting...\t"); + + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/armacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/swstartacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // notify start to acquisition thread + mtx_lock(&data.mtx); + data.acq_started = true; + mtx_unlock(&data.mtx); + cnd_signal(&data.cnd); + + printf("##########################################\n"); + printf("Commands supported:\n"); + printf("\t[%c]\tsend manual trigger\n", COMMAND_TRIGGER); + printf("\t[%c]\tstop acquisition\n", COMMAND_STOP); + printf("##########################################\n"); + + bool do_quit = false; + + do { + const int c = _getch(); + switch (c) { + case COMMAND_TRIGGER: { + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/sendswtrigger"); + if (ret != CAEN_FELib_Success) + print_last_error(); + break; + } + case COMMAND_STOP: { + do_quit = true; + break; + } + case '\n': { + break; + } + default: { + fprintf(stderr, "unknown command [%c]", c); + break; + } + } + } while (!do_quit); + + printf("\nStopping...\t"); + + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/disarmacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // wait the end of the acquisition + // that is going to finish just after the last event + int thrd_ret; + ret = thrd_join(thrd, &thrd_ret); + if (ret != thrd_success || thrd_ret != EXIT_SUCCESS) { + fprintf(stderr, "thrd_join error.\tret %d\tthrd_ret %d\n", ret, thrd_ret); + return EXIT_FAILURE; + } + mtx_destroy(&data.mtx); + cnd_destroy(&data.cnd); + + ret = CAEN_FELib_Close(dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("\nBye!\n"); + + return EXIT_SUCCESS; +} diff --git a/demo/caen-felib-demo-python/demo_dpppsd.py b/demo/caen-felib-demo-python/demo_dpppsd.py new file mode 100644 index 0000000..5da7a16 --- /dev/null +++ b/demo/caen-felib-demo-python/demo_dpppsd.py @@ -0,0 +1,159 @@ +""" +Python demo for Dig2 digitizers running a DPP-PSD firmware. +""" + +__author__ = 'Giovanni Cerretani' +__copyright__ = 'Copyright (C) 2023 CAEN SpA' +__license__ = 'MIT-0' # SPDX-License-Identifier +__contact__ = 'https://www.caen.it/' + +import matplotlib.pyplot as plt +import numpy as np + +# To install the module: pip install caen-felib +from caen_felib import lib, device, error + +print(f'CAEN FELib wrapper loaded (lib version {lib.version})') + +### CONNECTION PARAMETERS ### +address = '192.0.2.1' +############################# + +dig2_scheme = 'dig2' +dig2_authority = address +dig2_query = '' +dig2_path = '' +dig2_uri = f'{dig2_scheme}://{dig2_authority}/{dig2_path}?{dig2_query}' + +# Connect +with device.connect(dig2_uri) as dig: + + # Reset + dig.cmd.RESET() + + # Get board info + adc_samplrate_msps = float(dig.par.ADC_SAMPLRATE.value) # in Msps + adc_n_bits = int(dig.par.ADC_NBIT.value) + sampling_period_ns = int(1e3 / adc_samplrate_msps) + fw_type = dig.par.FWTYPE.value + + # Configuration parameters + reclen_ns = 4096 # in ns + pretrg_ns = 512 # in ns + + # Configure digitizer + dig.par.GLOBALTRIGGERSOURCE.value = 'SWTRG' # Enable software triggers + for i, ch in enumerate(dig.ch): + ch.par.CHENABLE.value = 'TRUE' if i == 0 else 'FALSE' # Enable only channel 0 + ch.par.EVENTTRIGGERSOURCE.value = 'GLOBALTRIGGERSOURCE' + ch.par.WAVETRIGGERSOURCE.value = 'GLOBALTRIGGERSOURCE' + ch.par.CHRECORDLENGTHT.value = f'{reclen_ns}' + ch.par.CHPRETRIGGERT.value = f'{pretrg_ns}' + ch.par.WAVEANALOGPROBE0.value = 'ADCINPUT' + ch.par.WAVEDIGITALPROBE0.value = 'TRIGGER' + + # Compute record length in samples + reclen_ns = int(dig.ch[0].par.CHRECORDLENGTHT.value) # Read back CHRECORDLENGTHT to check if there have been rounding + reclen = int(reclen_ns / sampling_period_ns) + + # Configure endpoint + data_format = [ + { + 'name': 'CHANNEL', + 'type': 'U8', + 'dim' : 0 + }, + { + 'name': 'TIMESTAMP', + 'type': 'U64', + 'dim': 0, + }, + { + 'name': 'ENERGY', + 'type': 'U16', + 'dim': 0, + }, + { + 'name': 'ANALOG_PROBE_1', + 'type': 'I16', + 'dim': 1, + 'shape': [reclen] + }, + { + 'name': 'ANALOG_PROBE_1_TYPE', + 'type': 'I32', + 'dim': 0 + }, + { + 'name': 'DIGITAL_PROBE_1', + 'type': 'U8', + 'dim': 1, + 'shape': [reclen] + }, + { + 'name': 'DIGITAL_PROBE_1_TYPE', + 'type': 'I32', + 'dim': 0 + }, + { + 'name': 'WAVEFORM_SIZE', + 'type': 'SIZE_T', + 'dim': 0 + } + ] + decoded_endpoint_path = 'dpppsd' + endpoint = dig.endpoint[decoded_endpoint_path] + data = endpoint.set_read_data_format(data_format) + dig.endpoint.par.ACTIVEENDPOINT.value = decoded_endpoint_path + + # Get reference to data fields + channel = data[0].value + timestamp = data[1].value + energy = data[2].value + analog_probe_1 = data[3].value + analog_probe_1_type = data[4].value # Integer value described in Supported Endpoints > Probe type meaning + digital_probe_1 = data[5].value + digital_probe_1_type = data[6].value # Integer value described in Supported Endpoints > Probe type meaning + waveform_size = data[7].value + + # Configure plot + plt.ion() + figure, ax = plt.subplots(figsize=(10, 8)) + lines = [] + for i in range(2): + line, = ax.plot([], [], drawstyle='steps-post') + lines.append(line) + ax.set_xlim(0, reclen - 1) + ax.set_ylim(0, 2 ** adc_n_bits - 1) + + # Start acquisition + dig.cmd.ARMACQUISITION() + dig.cmd.SWSTARTACQUISITION() + + # Read some events + for _ in range(1000): + # Send software trigger + dig.cmd.SENDSWTRIGGER() + + try: + endpoint.read_data(100, data) + except error.Error as ex: + if ex.code == error.ErrorCode.TIMEOUT: + continue + if ex.code == error.ErrorCode.STOP: + break + else: + raise ex + + assert analog_probe_1_type == 0 # 0 -> 'adc_input' + assert digital_probe_1_type == 0 # 0 -> 'trigger' + valid_sample_range = np.arange(0, waveform_size) + lines[0].set_data(valid_sample_range, analog_probe_1) + lines[1].set_data(valid_sample_range, digital_probe_1 * 2000 + 1000) # scale digital probe to be visible + + ax.title.set_text(f'Channel: {channel} Timestamp: {timestamp} Energy: {energy}') + + figure.canvas.draw() + figure.canvas.flush_events() + + dig.cmd.DISARMACQUISITION() diff --git a/demo/caen-felib-demo-python/demo_scope.py b/demo/caen-felib-demo-python/demo_scope.py new file mode 100644 index 0000000..c13741c --- /dev/null +++ b/demo/caen-felib-demo-python/demo_scope.py @@ -0,0 +1,127 @@ +""" +Python demo for Dig2 digitizers running a Scope firmware. +""" + +__author__ = 'Giovanni Cerretani' +__copyright__ = 'Copyright (C) 2024 CAEN SpA' +__license__ = 'MIT-0' # SPDX-License-Identifier +__contact__ = 'https://www.caen.it/' + +import matplotlib.pyplot as plt +import numpy as np + +# To install the module: pip install caen-felib +from caen_felib import lib, device, error + +print(f'CAEN FELib wrapper loaded (lib version {lib.version})') + +### CONNECTION PARAMETERS ### +address = '192.0.2.1' +############################# + +dig2_scheme = 'dig2' +dig2_authority = address +dig2_query = '' +dig2_path = '' +dig2_uri = f'{dig2_scheme}://{dig2_authority}/{dig2_path}?{dig2_query}' + +# Connect +with device.connect(dig2_uri) as dig: + + # Reset + dig.cmd.RESET() + + # Get board info + n_ch = int(dig.par.NUMCH.value) + adc_samplrate_msps = float(dig.par.ADC_SAMPLRATE.value) # in Msps + adc_n_bits = int(dig.par.ADC_NBIT.value) + sampling_period_ns = int(1e3 / adc_samplrate_msps) + fw_type = dig.par.FWTYPE.value + + # Configuration parameters + reclen_ns = 4096 # in ns + pretrg_ns = 512 # in ns + + # Configure digitizer + dig.par.RECORDLENGTHT.value = f'{reclen_ns}' + dig.par.PRETRIGGERT.value = f'{pretrg_ns}' + dig.par.ACQTRIGGERSOURCE.value = 'SWTRG' # Enable software triggers + + # Compute record length in samples + reclen_ns = int(dig.par.RECORDLENGTHT.value) # Read back RECORDLENGTHS to check if there have been rounding + reclen = int(reclen_ns / sampling_period_ns) + + # Configure endpoint + data_format = [ + { + 'name': 'EVENT_SIZE', + 'type': 'SIZE_T', + }, + { + 'name': 'TIMESTAMP', + 'type': 'U64', + }, + { + 'name': 'WAVEFORM', + 'type': 'U16', + 'dim': 2, + 'shape': [n_ch, reclen], + }, + { + 'name': 'WAVEFORM_SIZE', + 'type': 'U64', + 'dim': 1, + 'shape': [n_ch], + }, + ] + decoded_endpoint_path = 'scope' + endpoint = dig.endpoint[decoded_endpoint_path] + data = endpoint.set_read_data_format(data_format) + dig.endpoint.par.ACTIVEENDPOINT.value = decoded_endpoint_path + + # Get reference to data fields + event_size = data[0].value + timestamp = data[1].value + waveform = data[2].value + waveform_size = data[3].value + + # Configure plot + plt.ion() + figure, ax = plt.subplots(figsize=(10, 8)) + lines = [] + for i in range(n_ch): + line, = ax.plot([], [], drawstyle='steps-post') + lines.append(line) + ax.set_xlim(0, reclen - 1) + ax.set_ylim(0, 2 ** adc_n_bits - 1) + + # Start acquisition + dig.cmd.ARMACQUISITION() + dig.cmd.SWSTARTACQUISITION() + + # Read some events + for _ in range(1000): + # Send software trigger + dig.cmd.SENDSWTRIGGER() + + try: + endpoint.read_data(100, data) + except error.Error as ex: + if ex.code == error.ErrorCode.TIMEOUT: + continue + if ex.code == error.ErrorCode.STOP: + break + else: + raise ex + + # Plot first 4 channels + for i in range(n_ch): + valid_sample_range = np.arange(0, waveform_size[i]) + lines[i].set_data(valid_sample_range, waveform[i]) + + ax.title.set_text(f'Timestamp: {timestamp}') + + figure.canvas.draw() + figure.canvas.flush_events() + + dig.cmd.DISARMACQUISITION() diff --git a/demo/caen-felib-demo-scope/Makefile b/demo/caen-felib-demo-scope/Makefile new file mode 100644 index 0000000..b65eee4 --- /dev/null +++ b/demo/caen-felib-demo-scope/Makefile @@ -0,0 +1,20 @@ +TARGET = caen-felib-demo-scope +CFLAGS = -std=gnu11 -O2 -g -Wall -pthread +LDFLAGS = -pthread +LDLIBS = -lpthread -lCAEN_FELib + +.PHONY: default all clean + +default: $(TARGET) +all: default + +OBJECTS = main.o + +.PRECIOUS: $(TARGET) $(OBJECTS) + +$(TARGET): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $@ + +clean: + -rm -f *.o + -rm -f $(TARGET) diff --git a/demo/caen-felib-demo-scope/c11threads.h b/demo/caen-felib-demo-scope/c11threads.h new file mode 100644 index 0000000..cccf430 --- /dev/null +++ b/demo/caen-felib-demo-scope/c11threads.h @@ -0,0 +1,533 @@ +/* +c11threads + +Authors: + John Tsiombikas - original POSIX threads wrapper + Oliver Old - win32 implementation + +I place this piece of code in the public domain. Feel free to use as you see +fit. I'd appreciate it if you keep my name at the top of the code somewhere, but +whatever. + +Main project site: https://github.com/jtsiomb/c11threads +*/ +#ifndef C11THREADS_H_ +#define C11THREADS_H_ + +/* If you wish to use this with pthread-win32 (i.e. use the POSIX threads wrapper + * instead of the native win32 API implementation of C11 threads), then just + * define C11THREADS_PTHREAD_WIN32 before including this header file. + */ +#if defined(_WIN32) && !defined(C11THREADS_PTHREAD_WIN32) +#define C11THREADS_WIN32 +#endif + +/* If your compiler does not support the inline keyword, or supports it with + * some different variation of prefix or suffix underscores, you can define + * C11THREADS_INLINE before including this header file. + */ +#ifndef C11THREADS_INLINE +/* C99 compilers will have inline */ +#if __STDC_VERSION__ >= 199901L +#define C11THREADS_INLINE inline +/* C++ has inline */ +#elif defined(__cplusplus) +#define C11THREADS_INLINE inline +/* MSVC has inline from VS 2015 but supports __inline in older versions */ +#elif defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define C11THREADS_INLINE inline +#else +#define C11THREADS_INLINE __inline +#endif +/* for every other case, just gamble on having __inline__, and let the user + * define C11THREADS_INLINE if it breaks + */ +#else +#define C11THREADS_INLINE __inline__ +#endif +#endif /* !defined C11THREADS_INLINE */ + +#include + +#ifndef TIME_UTC +#define TIME_UTC 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*thrd_start_t)(void*); +typedef void (*tss_dtor_t)(void*); + +enum { + mtx_plain = 0, + mtx_recursive = 1, + mtx_timed = 2, +}; + +enum { + thrd_success, + thrd_timedout, + thrd_busy, + thrd_error, + thrd_nomem +}; + +#ifndef C11THREADS_WIN32 +/* C11 threads over POSIX threads as thin static inline wrapper functions */ +#include +#include +#include +#include /* for sched_yield */ +#include + +#ifndef thread_local +#define thread_local _Thread_local +#endif + +#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT +#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS + +#ifdef __APPLE__ +/* Darwin doesn't implement timed mutexes currently */ +#define C11THREADS_NO_TIMED_MUTEX +#include +#ifndef __MAC_10_15 +#define C11THREADS_NO_TIMESPEC_GET +#endif +#elif __STDC_VERSION__ < 201112L +#define C11THREADS_NO_TIMESPEC_GET +#endif + +#ifdef C11THREADS_NO_TIMED_MUTEX +#define C11THREADS_TIMEDLOCK_POLL_INTERVAL 5000000 /* 5 ms */ +#endif + +/* types */ +typedef pthread_t thrd_t; +typedef pthread_mutex_t mtx_t; +typedef pthread_cond_t cnd_t; +typedef pthread_key_t tss_t; +typedef pthread_once_t once_flag; + +/* ---- thread management ---- */ + +static C11THREADS_INLINE int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + int res = pthread_create(thr, 0, (void*(*)(void*))func, arg); + if(res == 0) { + return thrd_success; + } + return res == ENOMEM ? thrd_nomem : thrd_error; +} + +static C11THREADS_INLINE void thrd_exit(int res) +{ + pthread_exit((void*)(intptr_t)res); +} + +static C11THREADS_INLINE int thrd_join(thrd_t thr, int *res) +{ + void *retval; + + if(pthread_join(thr, &retval) != 0) { + return thrd_error; + } + if(res) { + *res = (int)(intptr_t)retval; + } + return thrd_success; +} + +static C11THREADS_INLINE int thrd_detach(thrd_t thr) +{ + return pthread_detach(thr) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE thrd_t thrd_current(void) +{ + return pthread_self(); +} + +static C11THREADS_INLINE int thrd_equal(thrd_t a, thrd_t b) +{ + return pthread_equal(a, b); +} + +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out) +{ + if(nanosleep(ts_in, rem_out) < 0) { + if(errno == EINTR) return -1; + return -2; + } + return 0; +} + +static C11THREADS_INLINE void thrd_yield(void) +{ + sched_yield(); +} + +/* ---- mutexes ---- */ + +static C11THREADS_INLINE int mtx_init(mtx_t *mtx, int type) +{ + int res; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + + if(type & mtx_timed) { +#ifdef PTHREAD_MUTEX_TIMED_NP + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP); +#else + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); +#endif + } + if(type & mtx_recursive) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + + res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error; + pthread_mutexattr_destroy(&attr); + return res; +} + +static C11THREADS_INLINE void mtx_destroy(mtx_t *mtx) +{ + pthread_mutex_destroy(mtx); +} + +static C11THREADS_INLINE int mtx_lock(mtx_t *mtx) +{ + int res = pthread_mutex_lock(mtx); + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_trylock(mtx_t *mtx) +{ + int res = pthread_mutex_trylock(mtx); + if(res == EBUSY) { + return thrd_busy; + } + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + int res = 0; +#ifdef C11THREADS_NO_TIMED_MUTEX + /* fake a timedlock by polling trylock in a loop and waiting for a bit */ + struct timeval now; + struct timespec sleeptime; + + sleeptime.tv_sec = 0; + sleeptime.tv_nsec = C11THREADS_TIMEDLOCK_POLL_INTERVAL; + + while((res = pthread_mutex_trylock(mtx)) == EBUSY) { + gettimeofday(&now, NULL); + + if(now.tv_sec > ts->tv_sec || (now.tv_sec == ts->tv_sec && + (now.tv_usec * 1000) >= ts->tv_nsec)) { + return thrd_timedout; + } + + nanosleep(&sleeptime, NULL); + } +#else + if((res = pthread_mutex_timedlock(mtx, ts)) == ETIMEDOUT) { + return thrd_timedout; + } +#endif + return res == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int mtx_unlock(mtx_t *mtx) +{ + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; +} + +/* ---- condition variables ---- */ + +static C11THREADS_INLINE int cnd_init(cnd_t *cond) +{ + return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void cnd_destroy(cnd_t *cond) +{ + pthread_cond_destroy(cond); +} + +static C11THREADS_INLINE int cnd_signal(cnd_t *cond) +{ + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_broadcast(cnd_t *cond) +{ + return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ + int res; + + if((res = pthread_cond_timedwait(cond, mtx, ts)) != 0) { + return res == ETIMEDOUT ? thrd_timedout : thrd_error; + } + return thrd_success; +} + +/* ---- thread-specific data ---- */ + +static C11THREADS_INLINE int tss_create(tss_t *key, tss_dtor_t dtor) +{ + return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void tss_delete(tss_t key) +{ + pthread_key_delete(key); +} + +static C11THREADS_INLINE int tss_set(tss_t key, void *val) +{ + return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error; +} + +static C11THREADS_INLINE void *tss_get(tss_t key) +{ + return pthread_getspecific(key); +} + +/* ---- misc ---- */ + +static C11THREADS_INLINE void call_once(once_flag *flag, void (*func)(void)) +{ + pthread_once(flag, func); +} + +#ifdef C11THREADS_NO_TIMESPEC_GET +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base) +{ + struct timeval tv; + + if(base != TIME_UTC) { + return 0; + } + + if(gettimeofday(&tv, 0) == -1) { + return 0; + } + + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + return base; +} +#endif + + +#else /* C11THREADS_WIN32 */ + +/* C11 threads implementation using native Win32 API calls (see c11threads_win32.c) */ + +#ifndef thread_local +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#else +#define thread_local _Thread_local +#endif +#endif + +#define ONCE_FLAG_INIT {0} +#define TSS_DTOR_ITERATIONS 4 + +#ifndef _UCRT +#define C11THREADS_NO_TIMESPEC_GET +#endif + +#ifdef _MSC_VER +#define C11THREADS_MSVC_NORETURN __declspec(noreturn) +#define C11THREADS_GNUC_NORETURN +#elif defined(__GNUC__) +#define C11THREADS_MSVC_NORETURN +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5) +#define C11THREADS_GNUC_NORETURN __attribute__((noreturn)) +#else +#define C11THREADS_GNUC_NORETURN +#endif +#else +#define C11THREADS_MSVC_NORETURN +#define C11THREADS_GNUC_NORETURN +#endif + +/* types */ +typedef unsigned long thrd_t; +typedef struct { + void *debug_info; + long lock_count; + long recursion_count; + void *owning_thread; + void *lock_semaphore; + void *spin_count; +} mtx_t; +typedef void *cnd_t; +typedef unsigned long tss_t; +typedef void *once_flag; +struct _c11threads_win32_timespec32_t { + long tv_sec; + long tv_nsec; +}; +struct _c11threads_win32_timespec64_t { +#ifdef _MSC_VER + __int64 tv_sec; +#else + long long tv_sec; +#endif + long tv_nsec; +}; +#if !defined(_UCRT) && !defined(_TIMESPEC_DEFINED) +#ifdef _USE_32BIT_TIME_T +struct timespec { + long tv_sec; + long tv_nsec; +}; +#elif !defined(_USE_32BIT_TIME_T) +struct timespec { + __int64 tv_sec; + long tv_nsec; +}; +#endif /* !defined(_USE_32BIT_TIME_T) */ +#endif /* !defined(_UCRT) && !defined(_TIMESPEC_DEFINED) */ + +/* Thread functions. */ + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); +/* Win32: Threads not created with thrd_create() need to call this to clean up TSS. */ +C11THREADS_MSVC_NORETURN void thrd_exit(int res) C11THREADS_GNUC_NORETURN; +int thrd_join(thrd_t thr, int *res); +int thrd_detach(thrd_t thr); +thrd_t thrd_current(void); +int thrd_equal(thrd_t a, thrd_t b); +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out); +void thrd_yield(void); + +/* Mutex functions. */ + +int mtx_init(mtx_t *mtx, int type); +void mtx_destroy(mtx_t *mtx); +int mtx_lock(mtx_t *mtx); +int mtx_trylock(mtx_t *mtx); +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); +int mtx_unlock(mtx_t *mtx); + +/* Condition variable functions. */ + +int cnd_init(cnd_t *cond); +void cnd_destroy(cnd_t *cond); +int cnd_signal(cnd_t *cond); +int cnd_broadcast(cnd_t *cond); +int cnd_wait(cnd_t *cond, mtx_t *mtx); +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); + +/* Thread-specific storage functions. */ + +int tss_create(tss_t *key, tss_dtor_t dtor); +void tss_delete(tss_t key); +int tss_set(tss_t key, void *val); +void *tss_get(tss_t key); + +/* One-time callable function. */ + +void call_once(once_flag *flag, void (*func)(void)); + +#ifdef C11THREADS_NO_TIMESPEC_GET +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base); +#endif + +/* Special Win32 functions. */ +/* Win32: Free resources associated with this library. */ +void c11threads_win32_destroy(void); +/* Win32: Register current Win32 thread in c11threads to allow for proper thrd_join(). */ +int c11threads_win32_thrd_self_register(void); +/* Win32: Register Win32 thread by ID in c11threads to allow for proper thrd_join(). */ +int c11threads_win32_thrd_register(unsigned long win32_thread_id); + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) /* Warning C4127: conditional expression is constant */ +#endif + +/* ---- thread management ---- */ + +int _c11threads_win32_thrd_sleep32(const struct _c11threads_win32_timespec32_t *ts_in, struct _c11threads_win32_timespec32_t *rem_out); +int _c11threads_win32_thrd_sleep64(const struct _c11threads_win32_timespec64_t *ts_in, struct _c11threads_win32_timespec64_t *rem_out); +static C11THREADS_INLINE int thrd_sleep(const struct timespec *ts_in, struct timespec *rem_out) +{ + if (sizeof(ts_in->tv_sec) == 4) { + return _c11threads_win32_thrd_sleep32((const struct _c11threads_win32_timespec32_t*)ts_in, (struct _c11threads_win32_timespec32_t*)rem_out); + } else { + return _c11threads_win32_thrd_sleep64((const struct _c11threads_win32_timespec64_t*)ts_in, (struct _c11threads_win32_timespec64_t*)rem_out); + } +} + +/* ---- mutexes ---- */ + +int _c11threads_win32_mtx_timedlock32(mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts); +int _c11threads_win32_mtx_timedlock64(mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts); +static C11THREADS_INLINE int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_mtx_timedlock32(mtx, (const struct _c11threads_win32_timespec32_t*)ts); + } else { + return _c11threads_win32_mtx_timedlock64(mtx, (const struct _c11threads_win32_timespec64_t*)ts); + } +} + +/* ---- condition variables ---- */ + +int _c11threads_win32_cnd_timedwait32(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts); +int _c11threads_win32_cnd_timedwait64(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts); +static C11THREADS_INLINE int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_cnd_timedwait32(cond, mtx, (const struct _c11threads_win32_timespec32_t*)ts); + } else { + return _c11threads_win32_cnd_timedwait64(cond, mtx, (const struct _c11threads_win32_timespec64_t*)ts); + } +} + +/* ---- misc ---- */ + +#ifdef C11THREADS_NO_TIMESPEC_GET +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base); +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base); +static C11THREADS_INLINE int timespec_get(struct timespec *ts, int base) +{ + if (sizeof(ts->tv_sec) == 4) { + return _c11threads_win32_timespec32_get((struct _c11threads_win32_timespec32_t*)ts, base); + } else { + return _c11threads_win32_timespec64_get((struct _c11threads_win32_timespec64_t*)ts, base); + } +} +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif /* C11THREADS_WIN32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* C11THREADS_H_ */ diff --git a/demo/caen-felib-demo-scope/c11threads_win32.c b/demo/caen-felib-demo-scope/c11threads_win32.c new file mode 100644 index 0000000..f8badec --- /dev/null +++ b/demo/caen-felib-demo-scope/c11threads_win32.c @@ -0,0 +1,1147 @@ +/* +Win32 implementation for c11threads. + +Authors: +John Tsiombikas +Oliver Old + +I place this piece of code in the public domain. Feel free to use as you see +fit. I'd appreciate it if you keep my name at the top of the code somewhere, but +whatever. + +Main project site: https://github.com/jtsiomb/c11threads +*/ + +#if defined(_WIN32) && !defined(C11THREADS_PTHREAD_WIN32) + +#ifdef _MSC_VER +/* Map debug malloc and free functions for debug builds. DO NOT CHANGE THE INCLUDE ORDER! */ +#define _CRTDBG_MAP_ALLOC +#include +#include +#endif + +#include "c11threads.h" + +#include +#include +#include + +#ifndef WINVER +#define WINVER 0x0400 /* Windows NT 4.0 */ +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT WINVER +#endif +#define WIN32_LEAN_AND_MEAN +#include + +#define _WIN32_WINNT_VISTA 0x0600 +#define THREAD_QUERY_LIMITED_INFORMATION (0x0800) + + +/* ---- library ---- */ + +typedef void (__stdcall *_c11threads_win32_InitializeConditionVariable_t)(void*); +typedef void (__stdcall *_c11threads_win32_WakeConditionVariable_t)(void*); +typedef void (__stdcall *_c11threads_win32_WakeAllConditionVariable_t)(void*); +typedef int (__stdcall *_c11threads_win32_SleepConditionVariableCS_t)(void*, PCRITICAL_SECTION, unsigned long); +typedef int (__stdcall *_c11threads_win32_InitOnceExecuteOnce_t)(void*, const void*, void*, void**); + +struct _c11threads_win32_thrd_entry_t { + struct _c11threads_win32_thrd_entry_t *next; + void *h; + thrd_t thrd; +}; + +struct _c11threads_win32_tss_dtor_entry_t { + struct _c11threads_win32_tss_dtor_entry_t *next; + tss_dtor_t dtor; + tss_t key; +}; + +static volatile long _c11threads_win32_initialized = 0; +static unsigned short _c11threads_win32_winver; +static _c11threads_win32_InitializeConditionVariable_t _c11threads_win32_InitializeConditionVariable; +static _c11threads_win32_WakeConditionVariable_t _c11threads_win32_WakeConditionVariable; +static _c11threads_win32_WakeAllConditionVariable_t _c11threads_win32_WakeAllConditionVariable; +static _c11threads_win32_SleepConditionVariableCS_t _c11threads_win32_SleepConditionVariableCS; +static _c11threads_win32_InitOnceExecuteOnce_t _c11threads_win32_InitOnceExecuteOnce; +static CRITICAL_SECTION _c11threads_win32_thrd_list_critical_section; +static struct _c11threads_win32_thrd_entry_t *_c11threads_win32_thrd_list_head = NULL; +static CRITICAL_SECTION _c11threads_win32_tss_dtor_list_critical_section; +static struct _c11threads_win32_tss_dtor_entry_t *_c11threads_win32_tss_dtor_list_head = NULL; + +#ifdef _MSC_VER +#pragma warning(push) +/* Warning C4996: 'GetVersion': was declared deprecated */ +/* Warning C28125: The function 'InitializeCriticalSection' must be called from within a try/except block. */ +/* Warning C28159: Consider using 'IsWindows*' instead of 'GetVersion'. Reason: Deprecated. Use VerifyVersionInfo* or IsWindows* macros from VersionHelpers. */ +#pragma warning(disable: 4996 28125 28159) +#endif +static void _c11threads_win32_init(void) +{ + unsigned short os_version; + os_version = (unsigned short)GetVersion(); /* Keep in mind: Maximum version for unmanifested apps is Windows 8 (0x0602). */ + _c11threads_win32_winver = (os_version << 8) | (os_version >> 8); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + void *kernel32; + kernel32 = GetModuleHandleW(L"kernel32.dll"); + if (!kernel32) { + abort(); + } + _c11threads_win32_InitializeConditionVariable = (_c11threads_win32_InitializeConditionVariable_t)GetProcAddress(kernel32, "InitializeConditionVariable"); + if (!_c11threads_win32_InitializeConditionVariable) { + abort(); + } + _c11threads_win32_WakeConditionVariable = (_c11threads_win32_WakeConditionVariable_t)GetProcAddress(kernel32, "WakeConditionVariable"); + if (!_c11threads_win32_WakeConditionVariable) { + abort(); + } + _c11threads_win32_WakeAllConditionVariable = (_c11threads_win32_WakeAllConditionVariable_t)GetProcAddress(kernel32, "WakeAllConditionVariable"); + if (!_c11threads_win32_WakeAllConditionVariable) { + abort(); + } + _c11threads_win32_SleepConditionVariableCS = (_c11threads_win32_SleepConditionVariableCS_t)GetProcAddress(kernel32, "SleepConditionVariableCS"); + if (!_c11threads_win32_SleepConditionVariableCS) { + abort(); + } + _c11threads_win32_InitOnceExecuteOnce = (_c11threads_win32_InitOnceExecuteOnce_t)GetProcAddress(kernel32, "InitOnceExecuteOnce"); + if (!_c11threads_win32_InitOnceExecuteOnce) { + abort(); + } + } + InitializeCriticalSection(&_c11threads_win32_thrd_list_critical_section); + InitializeCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static void _c11threads_win32_ensure_initialized(void) +{ + if (InterlockedCompareExchange(&_c11threads_win32_initialized, 1, 0) == 0) { + _c11threads_win32_init(); + InterlockedExchange(&_c11threads_win32_initialized, 2); + } else { +#ifdef _MSC_VER +#pragma warning(suppress: 28112) /* Warning C28112: A variable (_c11threads_win32_initialized) which is accessed via an Interlocked function must always be accessed via an Interlocked function. */ +#endif + while (_c11threads_win32_initialized == 1) { + Sleep(0); + } + } +} + +void c11threads_win32_destroy(void) +{ + struct _c11threads_win32_thrd_entry_t *thrd_entry; + struct _c11threads_win32_thrd_entry_t *thrd_entry_temp; + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry; + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry_temp; + + if (_c11threads_win32_initialized) { + DeleteCriticalSection(&_c11threads_win32_thrd_list_critical_section); + DeleteCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + thrd_entry = _c11threads_win32_thrd_list_head; + while (thrd_entry) { + thrd_entry_temp = thrd_entry->next; + CloseHandle(thrd_entry->h); + free(thrd_entry); + thrd_entry = thrd_entry_temp; + } + + tss_dtor_entry = _c11threads_win32_tss_dtor_list_head; + while (tss_dtor_entry) { + tss_dtor_entry_temp = tss_dtor_entry->next; + TlsFree(tss_dtor_entry->key); + free(tss_dtor_entry); + tss_dtor_entry = tss_dtor_entry_temp; + } + + _c11threads_win32_initialized = 0; + _c11threads_win32_thrd_list_head = NULL; + _c11threads_win32_tss_dtor_list_head = NULL; + } +} + +/* ---- utilities ---- */ + +static int _c11threads_win32_util_is_timespec32_valid(const struct _c11threads_win32_timespec32_t *ts) +{ + return ts->tv_sec >= 0 && ts->tv_nsec >= 0 && ts->tv_nsec <= 999999999; +} + +static int _c11threads_win32_util_is_timespec64_valid(const struct _c11threads_win32_timespec64_t *ts) +{ + return ts->tv_sec >= 0 && ts->tv_nsec >= 0 && ts->tv_nsec <= 999999999; +} + +/* Precondition: 'ts' validated. */ +static __int64 _c11threads_win32_util_timespec32_to_file_time(const struct _c11threads_win32_timespec32_t *ts) +{ + unsigned __int64 sec_res; + unsigned __int64 nsec_res; + + sec_res = (unsigned __int64)ts->tv_sec * (unsigned __int64)10000000; + + /* Add another 100 ns if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 100UL + !!((unsigned long)ts->tv_nsec % 100UL); + + return sec_res + nsec_res; +} + +/* Precondition: 'ts' validated. */ +static __int64 _c11threads_win32_util_timespec64_to_file_time(const struct _c11threads_win32_timespec64_t *ts, size_t *periods) +{ + unsigned __int64 sec_res; + unsigned __int64 nsec_res; + unsigned __int64 res; + + *periods = (unsigned long)((unsigned __int64)ts->tv_sec / (unsigned __int64)922337203685); + sec_res = ((unsigned __int64)ts->tv_sec % (unsigned __int64)922337203685) * (unsigned __int64)10000000; + + /* Add another 100 ns if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 100UL + !!((unsigned long)ts->tv_nsec % 100UL); + + /* 64-bit time_t may cause overflow. */ + if (nsec_res > (unsigned __int64) - 1 - sec_res) { + ++*periods; + nsec_res -= (unsigned __int64) - 1 - sec_res; + sec_res = 0; + } + + res = sec_res + nsec_res; + + if (*periods && !res) { + --*periods; + return (__int64)9223372036850000000; + } + + return res; +} + +/* Precondition: 'ts' validated. */ +static int _c11threads_win32_util_timespec32_to_milliseconds(const struct _c11threads_win32_timespec32_t *ts, unsigned long *ms) +{ + unsigned long sec_res; + unsigned long nsec_res; + + /* Overflow. */ + if ((unsigned long)ts->tv_sec > (INFINITE - 1UL) / 1000UL) { + return 0; + } + + sec_res = (unsigned long)ts->tv_sec * 1000UL; + /* Add another millisecond if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 1000000UL + !!((unsigned long)ts->tv_nsec % 1000000UL); + + /* Overflow. */ + if (nsec_res > INFINITE - 1UL - sec_res) { + return 0; + } + + *ms = sec_res + nsec_res; + return 1; +} + +/* Precondition: 'ts' validated. */ +static int _c11threads_win32_util_timespec64_to_milliseconds(const struct _c11threads_win32_timespec64_t *ts, unsigned long *ms) +{ + unsigned long sec_res; + unsigned long nsec_res; + + /* Overflow. */ + if ((unsigned __int64)ts->tv_sec > (INFINITE - 1UL) / 1000UL) { + return 0; + } + + sec_res = (unsigned long)ts->tv_sec * 1000UL; + /* Add another millisecond if division yields remainder. */ + nsec_res = (unsigned long)ts->tv_nsec / 1000000UL + !!((unsigned long)ts->tv_nsec % 1000000UL); + + /* Overflow. */ + if (nsec_res > INFINITE - 1UL - sec_res) { + return 0; + } + + *ms = sec_res + nsec_res; + return 1; +} + +/* Precondition: 'current_time' and 'end_time' validated. */ +static unsigned long _c11threads_win32_util_timepoint_to_millisecond_timespan32(const struct _c11threads_win32_timespec32_t *current_time, const struct _c11threads_win32_timespec32_t *end_time, int *clamped) { + unsigned long wait_time; + struct _c11threads_win32_timespec32_t ts; + + *clamped = 0; + if (current_time->tv_sec > end_time->tv_sec || (current_time->tv_sec == end_time->tv_sec && current_time->tv_nsec >= end_time->tv_nsec)) { + wait_time = 0; + } else { + ts.tv_sec = end_time->tv_sec - current_time->tv_sec; + ts.tv_nsec = end_time->tv_nsec - current_time->tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000; + } + + if (!_c11threads_win32_util_timespec32_to_milliseconds(&ts, &wait_time)) { + /* Clamp wait_time. Pretend we've had a spurious wakeup if expired. */ + wait_time = INFINITE - 1; + *clamped = 1; + } + } + + return wait_time; +} + +/* Precondition: 'current_time' and 'end_time' validated. */ +static unsigned long _c11threads_win32_util_timepoint_to_millisecond_timespan64(const struct _c11threads_win32_timespec64_t *current_time, const struct _c11threads_win32_timespec64_t *end_time, int *clamped) { + unsigned long wait_time; + struct _c11threads_win32_timespec64_t ts; + + *clamped = 0; + if (current_time->tv_sec > end_time->tv_sec || (current_time->tv_sec == end_time->tv_sec && current_time->tv_nsec >= end_time->tv_nsec)) { + wait_time = 0; + } else { + ts.tv_sec = end_time->tv_sec - current_time->tv_sec; + ts.tv_nsec = end_time->tv_nsec - current_time->tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000; + } + + if (!_c11threads_win32_util_timespec64_to_milliseconds(&ts, &wait_time)) { + /* Clamp wait_time. Pretend we've had a spurious wakeup if expired. */ + wait_time = INFINITE - 1; + *clamped = 1; + } + } + + return wait_time; +} + +#if defined(C11THREADS_NO_TIMESPEC_GET) || !defined(_MSC_VER) +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base) +{ + FILETIME file_time; + ULARGE_INTEGER li; + + if (base != TIME_UTC) { + return 0; + } + + GetSystemTimeAsFileTime(&file_time); + + li.LowPart = file_time.dwLowDateTime; + li.HighPart = file_time.dwHighDateTime; + + /* Also subtract difference between FILETIME and UNIX time epoch. It's 369 years by the way. */ + ts->tv_sec = (long)(li.QuadPart / (unsigned __int64)10000000 - (unsigned __int64)11644473600); + ts->tv_nsec = (long)(li.QuadPart % (unsigned __int64)10000000) * 100; + + return base; +} + +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base) +{ + FILETIME file_time; + ULARGE_INTEGER li; + + if (base != TIME_UTC) { + return 0; + } + + GetSystemTimeAsFileTime(&file_time); + + li.LowPart = file_time.dwLowDateTime; + li.HighPart = file_time.dwHighDateTime; + + /* Also subtract difference between FILETIME and UNIX time epoch. It's 369 years by the way. */ + ts->tv_sec = li.QuadPart / (unsigned __int64)10000000 - (unsigned __int64)11644473600; + ts->tv_nsec = (long)(li.QuadPart % (unsigned __int64)10000000) * 100; + + return base; +} +#else +int _c11threads_win32_timespec32_get(struct _c11threads_win32_timespec32_t *ts, int base) +{ + return _timespec32_get((struct _timespec32*)ts, base); +} + +int _c11threads_win32_timespec64_get(struct _c11threads_win32_timespec64_t *ts, int base) +{ + return _timespec64_get((struct _timespec64*)ts, base); +} +#endif + +/* ---- thread management ---- */ + +static int _c11threads_win32_thrd_register(thrd_t thrd, HANDLE h) +{ + struct _c11threads_win32_thrd_entry_t *thread_entry; + + thread_entry = malloc(sizeof(*thread_entry)); + if (!thread_entry) { + return 0; + } + + thread_entry->thrd = thrd; + thread_entry->h = h; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + thread_entry->next = _c11threads_win32_thrd_list_head; + _c11threads_win32_thrd_list_head = thread_entry; + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + return 1; +} + +static void *_c11threads_win32_thrd_pop_entry(thrd_t thrd) +{ + void *h; + struct _c11threads_win32_thrd_entry_t *prev; + struct _c11threads_win32_thrd_entry_t *curr; + struct _c11threads_win32_thrd_entry_t *next; + + h = NULL; + prev = NULL; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + curr = _c11threads_win32_thrd_list_head; + while (curr) + { + if (curr->thrd == thrd) { + h = curr->h; + next = curr->next; + if (prev) { + prev->next = next; + } else { + _c11threads_win32_thrd_list_head = next; + } + break; + } + + prev = curr; + curr = curr->next; + } + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + free(curr); + return h; +} + +static void _c11threads_win32_thrd_run_tss_dtors(void) +{ + int ran_dtor; + size_t i; + struct _c11threads_win32_tss_dtor_entry_t *prev; + struct _c11threads_win32_tss_dtor_entry_t *curr; + struct _c11threads_win32_tss_dtor_entry_t *next; + void *val; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + ran_dtor = 1; + for (i = 0; i < TSS_DTOR_ITERATIONS && ran_dtor; ++i) { + ran_dtor = 0; + prev = NULL; + curr = _c11threads_win32_tss_dtor_list_head; + + while (curr) { + val = TlsGetValue(curr->key); + if (val) { + TlsSetValue(curr->key, NULL); + curr->dtor(val); + ran_dtor = 1; + } else if (GetLastError() != ERROR_SUCCESS) { + next = curr->next; + free(curr); + if (prev) { + prev->next = next; + } else { + _c11threads_win32_tss_dtor_list_head = next; + } + curr = next; + continue; + } + + curr = curr->next; + } + } + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); +} + +int c11threads_win32_thrd_self_register(void) +{ + unsigned long desired_access; + void *process; + void *thread; + + desired_access = SYNCHRONIZE | THREAD_QUERY_INFORMATION; + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + desired_access = SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION; + } + + process = GetCurrentProcess(); + thread = GetCurrentThread(); + if (!DuplicateHandle(process, thread, process, &thread, desired_access, 0, 0)) { + return thrd_error; + } + if (!_c11threads_win32_thrd_register(GetCurrentThreadId(), thread)) { + CloseHandle(thread); + return thrd_nomem; + } + return thrd_success; +} + +int c11threads_win32_thrd_register(unsigned long win32_thread_id) +{ + /* XXX temporary hack to make this build on MSVC6. Investigate further */ +#ifdef _PROCESSTHREADSAPI_H_ + unsigned long desired_access; + void *h; + + desired_access = SYNCHRONIZE | THREAD_QUERY_INFORMATION; + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + desired_access = SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION; + } + + h = OpenThread(desired_access, 0, win32_thread_id); + if (!h) { + return thrd_error; + } + if (!_c11threads_win32_thrd_register(win32_thread_id, h)) { + CloseHandle(h); + return thrd_nomem; + } +#endif + return thrd_success; +} + +struct _c11threads_win32_thrd_start_thunk_parameters_t { + thrd_start_t func; + void *arg; +}; + +static int __stdcall _c11threads_win32_thrd_start_thunk(struct _c11threads_win32_thrd_start_thunk_parameters_t *start_parameters) +{ + int res; + struct _c11threads_win32_thrd_start_thunk_parameters_t local_start_params; + local_start_params = *start_parameters; + free(start_parameters); + res = local_start_params.func(local_start_params.arg); + _c11threads_win32_thrd_run_tss_dtors(); + return res; +} + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + struct _c11threads_win32_thrd_start_thunk_parameters_t *thread_start_params; + struct _c11threads_win32_thrd_entry_t *thread_entry; + void *h; + + thread_start_params = malloc(sizeof(*thread_start_params)); + if (!thread_start_params) { + return thrd_nomem; + } + + thread_start_params->func = func; + thread_start_params->arg = arg; + + thread_entry = malloc(sizeof(*thread_entry)); + if (!thread_entry) { + free(thread_start_params); + return thrd_nomem; + } + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_thrd_list_critical_section); + h = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)_c11threads_win32_thrd_start_thunk, thread_start_params, 0, thr); + if (!h) { + unsigned long error; + error = GetLastError(); + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + free(thread_start_params); + free(thread_entry); + return error == ERROR_NOT_ENOUGH_MEMORY ? thrd_nomem : thrd_error; + } + thread_entry->next = _c11threads_win32_thrd_list_head; + thread_entry->h = h; + thread_entry->thrd = *thr; + _c11threads_win32_thrd_list_head = thread_entry; + LeaveCriticalSection(&_c11threads_win32_thrd_list_critical_section); + + return thrd_success; +} + +void thrd_exit(int res) +{ + _c11threads_win32_thrd_run_tss_dtors(); + ExitThread(res); +} + +int thrd_join(thrd_t thr, int *res) +{ + int ret; + void *h; + + ret = thrd_error; + h = _c11threads_win32_thrd_pop_entry(thr); + if (h) { + if (WaitForSingleObject(h, INFINITE) == WAIT_OBJECT_0 && (!res || GetExitCodeThread(h, (unsigned long*)res))) { + ret = thrd_success; + } + + CloseHandle(h); + } + + return ret; +} + +int thrd_detach(thrd_t thr) +{ + void *h; + h = _c11threads_win32_thrd_pop_entry(thr); + return h && CloseHandle(h) ? thrd_success : thrd_error; +} + +thrd_t thrd_current(void) +{ + return GetCurrentThreadId(); +} + +static int _c11threads_win32_sleep_common(__int64 file_time_in) +{ + void *timer; + unsigned long error; + LARGE_INTEGER due_time; + + assert(file_time_in >= 0); + + timer = CreateWaitableTimerW(NULL, 1, NULL); + if (!timer) { + error = GetLastError(); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + due_time.QuadPart = -file_time_in; + if (!SetWaitableTimer(timer, &due_time, 0, NULL, NULL, 0)) { + error = GetLastError(); + CloseHandle(timer); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) { + error = GetLastError(); + CloseHandle(timer); + return error > 1 ? -(long)error : -ERROR_INTERNAL_ERROR; + } + + CloseHandle(timer); + return 0; /* Success. */ +} + +int _c11threads_win32_thrd_sleep32(const struct _c11threads_win32_timespec32_t *ts_in, struct _c11threads_win32_timespec32_t *rem_out) +{ + __int64 file_time; + int res; + + (void)rem_out; + + if (!_c11threads_win32_util_is_timespec32_valid(ts_in)) { + return -ERROR_INVALID_PARAMETER; + } + + file_time = _c11threads_win32_util_timespec32_to_file_time(ts_in); + if (file_time < 0) { + return -ERROR_INVALID_PARAMETER; + } + + res = _c11threads_win32_sleep_common(file_time); + + return res; +} + +int _c11threads_win32_thrd_sleep64(const struct _c11threads_win32_timespec64_t *ts_in, struct _c11threads_win32_timespec64_t *rem_out) +{ + __int64 file_time; + size_t periods; + int res; + + (void)rem_out; + + if (!_c11threads_win32_util_is_timespec64_valid(ts_in)) { + return -ERROR_INVALID_PARAMETER; + } + + file_time = _c11threads_win32_util_timespec64_to_file_time(ts_in, &periods); + if (file_time < 0) { + return -ERROR_INVALID_PARAMETER; + } + +restart_sleep: + res = _c11threads_win32_sleep_common(file_time); + + if (!res && periods) { + --periods; + file_time = (__int64)9223372036850000000; + goto restart_sleep; + } + + return res; +} + +void thrd_yield(void) +{ + SwitchToThread(); +} + +/* ---- mutexes ---- */ + +int mtx_init(mtx_t *mtx, int type) +{ + (void)type; +#ifdef _MSC_VER +#pragma warning(suppress: 28125) /* Warning C28125: The function 'InitializeCriticalSection' must be called from within a try/except block. */ +#endif + InitializeCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +void mtx_destroy(mtx_t *mtx) +{ + DeleteCriticalSection((PCRITICAL_SECTION)mtx); +} + +int mtx_lock(mtx_t *mtx) +{ + EnterCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +int mtx_trylock(mtx_t *mtx) +{ + return TryEnterCriticalSection((PCRITICAL_SECTION)mtx) ? thrd_success : thrd_busy; +} + +int _c11threads_win32_mtx_timedlock32(mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts) +{ + int success; + struct _c11threads_win32_timespec32_t ts_current; + + if (!_c11threads_win32_util_is_timespec32_valid(ts)) { + return thrd_error; + } + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + while (!success) { + if (!_c11threads_win32_timespec32_get(&ts_current, TIME_UTC)) { + return thrd_error; + } + + if (ts_current.tv_sec > ts->tv_sec || (ts_current.tv_sec == ts->tv_sec && ts_current.tv_nsec >= ts->tv_nsec)) { + return thrd_timedout; + } + + Sleep(0); + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + } + + return thrd_success; +} + +int _c11threads_win32_mtx_timedlock64(mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts) +{ + int success; + struct _c11threads_win32_timespec64_t ts_current; + + if (!_c11threads_win32_util_is_timespec64_valid(ts)) { + return thrd_error; + } + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + while (!success) { + if (!_c11threads_win32_timespec64_get(&ts_current, TIME_UTC)) { + return thrd_error; + } + + if (ts_current.tv_sec > ts->tv_sec || (ts_current.tv_sec == ts->tv_sec && ts_current.tv_nsec >= ts->tv_nsec)) { + return thrd_timedout; + } + + Sleep(0); + + success = TryEnterCriticalSection((PCRITICAL_SECTION)mtx); + } + + return thrd_success; +} + +int mtx_unlock(mtx_t *mtx) +{ + LeaveCriticalSection((PCRITICAL_SECTION)mtx); + return thrd_success; +} + +/* ---- condition variables ---- */ + +struct _c11threads_win32_cnd_t { + void *mutex; + void *signal_sema; + void *broadcast_event; + size_t wait_count; +}; + +int cnd_init(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_InitializeConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + + cnd = malloc(sizeof(*cnd)); + if (!cnd) { + return thrd_nomem; + } + + cnd->mutex = CreateMutexW(NULL, 0, NULL); + if (cnd->mutex) { + cnd->signal_sema = CreateSemaphoreW(NULL, 0, 0x7fffffff, NULL); + if (cnd->signal_sema) { + cnd->broadcast_event = CreateEventW(NULL, 1, 0, NULL); + if (cnd->broadcast_event) { + cnd->wait_count = 0; + *cond = cnd; + return thrd_success; + } + CloseHandle(cnd->signal_sema); + } + CloseHandle(cnd->mutex); + } + + free(cnd); + return thrd_error; + } +} + +void cnd_destroy(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver < _WIN32_WINNT_VISTA) { + struct _c11threads_win32_cnd_t *cnd; + cnd = *cond; + assert(!cnd->wait_count); + CloseHandle(cnd->mutex); + CloseHandle(cnd->signal_sema); + CloseHandle(cnd->broadcast_event); + free(cnd); + } +} + +int cnd_signal(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_WakeConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + int success; + unsigned long wait_status; + + cnd = *cond; + + success = 0; + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_OBJECT_0) { + success = 1; + } else if (wait_status == WAIT_ABANDONED) { + abort(); + } + + if (success) { + if (cnd->wait_count) { + success = ReleaseSemaphore(cnd->signal_sema, 1, NULL) || GetLastError() == ERROR_TOO_MANY_POSTS; + } + if (!ReleaseMutex(cnd->mutex)) { + success = 0; + } + } + + return success ? thrd_success : thrd_error; + } +} + +int cnd_broadcast(cnd_t *cond) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + _c11threads_win32_WakeAllConditionVariable(cond); + return thrd_success; + } else { + struct _c11threads_win32_cnd_t *cnd; + int success; + unsigned long wait_status; + + cnd = *cond; + + success = 0; + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_OBJECT_0) { + success = 1; + } else if (wait_status == WAIT_ABANDONED) { + abort(); + } + + if (success) { + if (cnd->wait_count) { + success = SetEvent(cnd->broadcast_event); + } + if (!ReleaseMutex(cnd->mutex)) { + success = 0; + } + } + + return success ? thrd_success : thrd_error; + } +} + +static int _c11threads_win32_cnd_wait_common(cnd_t *cond, mtx_t *mtx, unsigned long wait_time, int clamped) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { + if (_c11threads_win32_SleepConditionVariableCS(cond, (PCRITICAL_SECTION)mtx, wait_time)) { + return thrd_success; + } + + if (GetLastError() == ERROR_TIMEOUT) { + return clamped ? thrd_success : thrd_timedout; + } + + return thrd_error; + } else { + struct _c11threads_win32_cnd_t *cnd; + unsigned long wait_status; + unsigned long wait_status_2; + int res; + + cnd = *cond; + + wait_status = WaitForSingleObject(cnd->mutex, INFINITE); + if (wait_status == WAIT_ABANDONED) { + abort(); + } else if (wait_status != WAIT_OBJECT_0) { + return thrd_error; + } + LeaveCriticalSection((PCRITICAL_SECTION)mtx); + ++cnd->wait_count; + if (!ReleaseMutex(cnd->mutex)) { + abort(); + } + + wait_status = WaitForMultipleObjects(2, &cnd->signal_sema /* and cnd->broadcast_event */, 0, wait_time); + + if (WaitForSingleObject(cnd->mutex, INFINITE) != WAIT_OBJECT_0) { + abort(); + } + --cnd->wait_count; + if (!cnd->wait_count) { + do { + wait_status_2 = WaitForSingleObject(cnd->signal_sema, 0); + } while (wait_status_2 == WAIT_OBJECT_0); + if (wait_status_2 != WAIT_TIMEOUT) { + abort(); + } + + if (!ResetEvent(cnd->broadcast_event)) { + abort(); + } + } + if (!ReleaseMutex(cnd->mutex)) { + abort(); + } + + res = thrd_success; + if (wait_status == WAIT_TIMEOUT) { + if (!clamped) { + res = thrd_timedout; + } + } else if (wait_status != WAIT_OBJECT_0 && wait_status != WAIT_OBJECT_0 + 1) { + res = thrd_error; + } + + EnterCriticalSection((PCRITICAL_SECTION)mtx); + return res; + } +} + +int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return _c11threads_win32_cnd_wait_common(cond, mtx, INFINITE, 0); +} + +int _c11threads_win32_cnd_timedwait32(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec32_t *ts) +{ + struct _c11threads_win32_timespec32_t current_time; + unsigned long wait_time; + int clamped; + + if (!_c11threads_win32_util_is_timespec32_valid(ts)) { + return thrd_error; + } + + if (!_c11threads_win32_timespec32_get(¤t_time, TIME_UTC)) { + return thrd_error; + } + + wait_time = _c11threads_win32_util_timepoint_to_millisecond_timespan32(¤t_time, ts, &clamped); + + return _c11threads_win32_cnd_wait_common(cond, mtx, wait_time, clamped); +} + +int _c11threads_win32_cnd_timedwait64(cnd_t *cond, mtx_t *mtx, const struct _c11threads_win32_timespec64_t *ts) +{ + struct _c11threads_win32_timespec64_t current_time; + unsigned long wait_time; + int clamped; + + if (!_c11threads_win32_util_is_timespec64_valid(ts)) { + return thrd_error; + } + + if (!_c11threads_win32_timespec64_get(¤t_time, TIME_UTC)) { + return thrd_error; + } + + wait_time = _c11threads_win32_util_timepoint_to_millisecond_timespan64(¤t_time, ts, &clamped); + + return _c11threads_win32_cnd_wait_common(cond, mtx, wait_time, clamped); +} + +/* ---- thread-specific data ---- */ + +static int _c11threads_win32_tss_register(tss_t key, tss_dtor_t dtor) { + struct _c11threads_win32_tss_dtor_entry_t *tss_dtor_entry; + + tss_dtor_entry = malloc(sizeof(*tss_dtor_entry)); + if (!tss_dtor_entry) { + return 0; + } + + tss_dtor_entry->key = key; + tss_dtor_entry->dtor = dtor; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + tss_dtor_entry->next = _c11threads_win32_tss_dtor_list_head; + _c11threads_win32_tss_dtor_list_head = tss_dtor_entry; + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + return 1; +} + +static void _c11threads_win32_tss_deregister(tss_t key) { + struct _c11threads_win32_tss_dtor_entry_t *prev; + struct _c11threads_win32_tss_dtor_entry_t *curr; + struct _c11threads_win32_tss_dtor_entry_t *next; + + prev = NULL; + + _c11threads_win32_ensure_initialized(); + EnterCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + curr = _c11threads_win32_tss_dtor_list_head; + while (curr) + { + if (curr->key == key) { + next = curr->next; + if (prev) { + prev->next = next; + } else { + _c11threads_win32_tss_dtor_list_head = next; + } + break; + } + + prev = curr; + curr = curr->next; + } + LeaveCriticalSection(&_c11threads_win32_tss_dtor_list_critical_section); + + free(curr); +} + +int tss_create(tss_t *key, tss_dtor_t dtor) +{ + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) { + return thrd_error; + } + if (dtor && !_c11threads_win32_tss_register(*key, dtor)) { + TlsFree(*key); + return thrd_error; + } + return thrd_success; +} + +void tss_delete(tss_t key) +{ + _c11threads_win32_tss_deregister(key); + TlsFree(key); +} + +int tss_set(tss_t key, void *val) +{ + return TlsSetValue(key, val) ? thrd_success : thrd_error; +} + +void *tss_get(tss_t key) +{ + return TlsGetValue(key); +} + +/* ---- misc ---- */ + +static int __stdcall _c11threads_win32_call_once_thunk(void *init_once, void (*func)(void), void **context) +{ + (void)init_once; + (void)context; + func(); + return 1; +} + +void call_once(once_flag *flag, void (*func)(void)) +{ + _c11threads_win32_ensure_initialized(); + if (_c11threads_win32_winver >= _WIN32_WINNT_VISTA) { +#ifdef _MSC_VER +#pragma warning(push) +/* Warning C4054: 'type cast' : from function pointer 'int (__stdcall *)(void *,void (__cdecl *)(void),void **)' to data pointer 'const void *' */ +/* Warning C4054: 'type cast' : from function pointer 'void (__cdecl *)(void)' to data pointer 'void *' */ +#pragma warning(disable: 4054) +#endif + _c11threads_win32_InitOnceExecuteOnce((void*)flag, (const void*)_c11threads_win32_call_once_thunk, (void*)func, NULL); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } else { + if (InterlockedCompareExchange((long*)flag, 1, 0) == 0) { + func(); + InterlockedExchange((long*)flag, 2); + } else { + while (*(volatile long*)flag == 1) { + Sleep(0); + } + } + } +} + +#endif diff --git a/demo/caen-felib-demo-scope/caen-felib-demo-scope.vcxproj b/demo/caen-felib-demo-scope/caen-felib-demo-scope.vcxproj new file mode 100644 index 0000000..737feaf --- /dev/null +++ b/demo/caen-felib-demo-scope/caen-felib-demo-scope.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {73930575-B5DD-4121-BE63-33B498CED63E} + caenfelibdemoscope + 10.0.16299.0 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-scope/caen-felib-demo-scope.vcxproj.filters b/demo/caen-felib-demo-scope/caen-felib-demo-scope.vcxproj.filters new file mode 100644 index 0000000..ef7db9a --- /dev/null +++ b/demo/caen-felib-demo-scope/caen-felib-demo-scope.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-scope/main.c b/demo/caen-felib-demo-scope/main.c new file mode 100644 index 0000000..ff67a87 --- /dev/null +++ b/demo/caen-felib-demo-scope/main.c @@ -0,0 +1,715 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +* SPDX-License-Identifier: MIT-0 +* +***************************************************************************//*! +* +* \file main.c +* \brief CAEN Open FPGA Digitzers Scope demo +* \author Giovanni Cerretani +* +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// windows or C11 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_THREADS__) +#include +#else +#include "c11threads.h" +#endif + +#include + +// Basic hardcoded configuration +#define COMMAND_TRIGGER 't' +#define COMMAND_STOP 'q' +#define COMMAND_PLOT_WAVE 'w' +#define MAX_NUMBER_OF_SAMPLES (1U << 10) +#define TIMEOUT_MS (100) +#define WAVE_FILE_NAME "Wave.txt" +#define WAVE_FILE_ENABLED false +#define EVT_FILE_NAME "EventInfo.txt" +#define EVT_FILE_ENABLED false +#define DATA_FORMAT " \ + [ \ + { \"name\" : \"TIMESTAMP\", \"type\" : \"U64\" }, \ + { \"name\" : \"TRIGGER_ID\", \"type\" : \"U32\" }, \ + { \"name\" : \"WAVEFORM\", \"type\" : \"U16\", \"dim\" : 2 }, \ + { \"name\" : \"WAVEFORM_SIZE\", \"type\" : \"SIZE_T\", \"dim\" : 1 }, \ + { \"name\" : \"EVENT_SIZE\", \"type\" : \"SIZE_T\" } \ + ] \ +" + +// Utilities +#define ARRAY_SIZE(X) (sizeof(X)/sizeof((X)[0])) + +#ifdef _WIN32 // Windows +#include +#define GNUPLOT "pgnuplot.exe" +#else // Linux +#include +#include +#define GNUPLOT "gnuplot" +#define _popen(command, type) popen(command, type) +#define _pclose(command) pclose(command) +// Linux replacement for non standard _getch +static int _getch() { + struct termios oldattr; + if (tcgetattr(STDIN_FILENO, &oldattr) == -1) perror(NULL); + struct termios newattr = oldattr; + newattr.c_lflag &= ~(ICANON | ECHO); + if (tcsetattr(STDIN_FILENO, TCSANOW, &newattr) == -1) perror(NULL); + const int ch = getchar(); + if (tcsetattr(STDIN_FILENO, TCSANOW, &oldattr) == -1) perror(NULL); + return ch; +} +#endif + +static unsigned long long value_to_ull(const char* value) { + char* value_end; + const unsigned long long ret = strtoull(value, &value_end, 0); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtoull error\n"); + return ret; +} + +static double value_to_d(const char* value) { + char* value_end; + const double ret = strtod(value, &value_end); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtod error\n"); + return ret; +} + +static int print_last_error(void) { + char msg[1024]; + int ec = CAEN_FELib_GetLastError(msg); + if (ec != CAEN_FELib_Success) { + fprintf(stderr, "%s failed\n", __func__); + return ec; + } + fprintf(stderr, "last error: %s\n", msg); + return ec; +} + +static int connect_to_digitizer(uint64_t* dev_handle, int argc, char* argv[]) { + const char* path; + char local_path[256]; + printf("device path: "); + if (argc == 2) { + path = argv[1]; + puts(path); + } else { + while (fgets(local_path, sizeof(local_path), stdin) == NULL); + local_path[strcspn(local_path, "\r\n")] = '\0'; // remove newline added by fgets + path = local_path; + } + return CAEN_FELib_Open(path, dev_handle); +} + +static int get_n_channels(uint64_t dev_handle, size_t* n_channels) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + *n_channels = (size_t)value_to_ull(value); + return ret; +} + +static int print_digitizer_details(uint64_t dev_handle) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/ModelName", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Model name:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/SerialNum", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Serial number:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_Nbit", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC bits:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Channels:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_SamplRate", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC rate:\t%f Msps\n", value_to_d(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/cupver", value); + if (ret != CAEN_FELib_Success) return ret; + printf("CUP version:\t%s\n", value); + return ret; +} + +static int configure_digitizer(uint64_t dev_handle, size_t n_channels) { + + int ret; + char value[256]; + char par_name[256]; + + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChEnable", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "true"); + if (ret != CAEN_FELib_Success) return ret; + + const unsigned int record_length = 1024; // in samples + snprintf(value, sizeof(value), "%u", record_length); + ret = CAEN_FELib_SetValue(dev_handle, "/par/RecordLengthS", value); + if (ret != CAEN_FELib_Success) return ret; + + assert(record_length <= MAX_NUMBER_OF_SAMPLES); + + const unsigned int pre_trigger = 100; // in samples + snprintf(value, sizeof(value), "%u", pre_trigger); + ret = CAEN_FELib_SetValue(dev_handle, "/par/PreTriggerS", value); + if (ret != CAEN_FELib_Success) return ret; + + ret = CAEN_FELib_SetValue(dev_handle, "/par/AcqTriggerSource", "SwTrg | TestPulse"); + if (ret != CAEN_FELib_Success) return ret; + + const double pulse_period = 100e6; // in nsec + snprintf(value, sizeof(value), "%f", pulse_period); + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulsePeriod", value); + if (ret != CAEN_FELib_Success) return ret; + + const unsigned int pulse_width = 1000; // in nsec + snprintf(value, sizeof(value), "%u", pulse_width); + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulseWidth", value); + if (ret != CAEN_FELib_Success) return ret; + + const double dc_offset = 50.; // in percent + snprintf(value, sizeof(value), "%f", dc_offset); + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/DCOffset", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, value); + if (ret != CAEN_FELib_Success) return ret; + + return ret; + +} + +static int configure_endpoint(uint64_t ep_handle) { + int ret; + // conigure endpoint + uint64_t ep_folder_handle; + ret = CAEN_FELib_GetParentHandle(ep_handle, NULL, &ep_folder_handle); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(ep_folder_handle, "/par/activeendpoint", "scope"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetReadDataFormat(ep_handle, DATA_FORMAT); + if (ret != CAEN_FELib_Success) return ret; + return ret; +} + +struct counters { + size_t total_size; + size_t n_events; + time_t t_begin; +}; + +struct event { + uint64_t timestamp; + double timestamp_us; + uint32_t trigger_id; + size_t event_size; + uint16_t** waveform; + size_t* n_samples; + size_t* n_allocated_samples; + size_t n_channels; +}; + +struct acq_data { + uint64_t dev_handle; + mtx_t mtx; + cnd_t cnd; + bool ep_configured; + bool acq_started; + size_t n_channels; + bool plot_next_wave; +}; + +struct plotters { + FILE* gnuplot_w; +}; + +static void print_stats(double t, size_t n_events, double rate) { + printf("\x1b[1K\rTime (s): %.1f\tEvents: %zu\tReadout rate (MB/s): %f", t, n_events, rate); + fflush(stdout); +} + +static void plot_waveform(FILE* gnuplot, struct event* evt) { + FILE* f_wave = fopen(WAVE_FILE_NAME, "w"); + if (f_wave == NULL) { + fprintf(stderr, "fopen failed"); + thrd_exit(EXIT_FAILURE); + } + // get max n_samples + size_t max_n_samples = 0; + for (size_t ch = 0; ch < evt->n_channels; ++ch) { + if (evt->n_samples[ch] > max_n_samples) + max_n_samples = evt->n_samples[ch]; + } + // title + for (size_t ch = 0; ch < evt->n_channels; ++ch) { + const bool last_ch = (ch == evt->n_channels - 1); + fprintf(f_wave, "CH%zu%c", ch, last_ch ? '\n' : '\t'); + } + // waveform + for (size_t i = 0; i < max_n_samples; ++i) { + for (size_t ch = 0; ch < evt->n_channels; ++ch) { + const bool last_ch = (ch == evt->n_channels - 1); + fprintf(f_wave, "%"PRIu16"%c", evt->waveform[ch][i], last_ch ? '\n' : '\t'); + } + } + fclose(f_wave); + fprintf(gnuplot, "set title 'Waveform (timestamp %.3f us)'\n", evt->timestamp_us); + for (size_t i = 0; i < evt->n_channels; ++i) { + const bool first_ch = (i == 0); + const bool last_ch = (i == evt->n_channels - 1); + if (first_ch) + fprintf(gnuplot, "plot '%s' using %zu with step", WAVE_FILE_NAME, i + 1); + else + fprintf(gnuplot, ", '' using %zu with step", i + 1); + if (last_ch) + fputc('\n', gnuplot); + } + fflush(gnuplot); +} + +static void save_event(FILE* f_evt, FILE* f_wave, struct event* evt) { + + const bool save_event = f_evt != NULL; + const bool save_wave = f_wave != NULL; + const bool save_enabled = save_event || save_wave; + + if (save_enabled) { + char str[256]; + snprintf(str, sizeof(str), "ts: %.3f us\t\ttrg_id: %"PRIu32"\t\tnum_samples: %zu\n", evt->timestamp_us, evt->trigger_id, evt->n_samples[0]); + if (save_event) { + fputs(str, f_evt); + } + if (save_wave) { + fputs(str, f_wave); + for (size_t i = 0; i < evt->n_channels; ++i) { + const size_t ch_size = evt->n_samples[i]; + if (ch_size > 0) { + fprintf(f_wave, "CH_%zu\n", i); + for (size_t s = 0; s < ch_size; ++s) + fprintf(f_wave, "%"PRIu16"\n", evt->waveform[i][s]); + } + } + } + } + +} + +static double counters_dt(struct counters* c, time_t t) { + return difftime(t, c->t_begin); +} + +static double counters_rate(struct counters* c, time_t t) { + return c->total_size / counters_dt(c, t) / (1024. * 1024.); // MB/s +} + +static void counters_increment(struct counters* c, size_t size) { + c->total_size += size; + ++c->n_events; +} + +static void counters_reset(struct counters* c, time_t t) { + c->total_size = 0; + c->n_events = 0; + c->t_begin = t; +} + +static void read_data_loop(struct plotters* plotters, FILE* f_evt, FILE* f_wave, struct acq_data* acq_data, uint64_t ep_handle, struct event* evt) { + + struct counters total; + struct counters interval; + + counters_reset(&total, time(NULL)); + counters_reset(&interval, total.t_begin); + + for (;;) { + + const time_t current_time = time(NULL); + const double dt = counters_dt(&interval, current_time); + if (dt >= 1.) { + // print stats + print_stats(counters_dt(&total, current_time), total.n_events, counters_rate(&interval, current_time)); + counters_reset(&interval, current_time); + } + + const int ret = CAEN_FELib_ReadData(ep_handle, TIMEOUT_MS, + &evt->timestamp, + &evt->trigger_id, + evt->waveform, + evt->n_samples, + &evt->event_size + ); + switch (ret) { + case CAEN_FELib_Success: { + + counters_increment(&total, evt->event_size); + counters_increment(&interval, evt->event_size); + + evt->timestamp_us = evt->timestamp * .008; + + save_event(f_evt, f_wave, evt); + + mtx_lock(&acq_data->mtx); + if (acq_data->plot_next_wave) { + acq_data->plot_next_wave = false; + plot_waveform(plotters->gnuplot_w, evt); + } + mtx_unlock(&acq_data->mtx); + + break; + } + case CAEN_FELib_Timeout: + break; + case CAEN_FELib_Stop: + printf("\nStop received.\n"); + return; + default: + print_last_error(); + break; + } + } +} + +static struct event* allocate_event(size_t n_samples, size_t n_channels) { + struct event* evt = malloc(sizeof(*evt)); + if (evt == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->n_channels = n_channels; + evt->n_samples = malloc(evt->n_channels * sizeof(*evt->n_samples)); + if (evt->n_samples == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->n_allocated_samples = malloc(evt->n_channels * sizeof(*evt->n_allocated_samples)); + if (evt->n_allocated_samples == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->waveform = malloc(evt->n_channels * sizeof(*evt->waveform)); + if (evt->waveform == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + for (size_t i = 0; i < evt->n_channels; ++i) { + evt->n_allocated_samples[i] = n_samples; + evt->waveform[i] = malloc(evt->n_allocated_samples[i] * sizeof(*evt->waveform[i])); + if (evt->waveform[i] == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + } + return evt; +} + +static void free_event(struct event* evt) { + for (size_t i = 0; i < evt->n_channels; ++i) + free(evt->waveform[i]); + free(evt->waveform); + free(evt->n_allocated_samples); + free(evt->n_samples); + free(evt); +} + +static struct plotters* open_plotters() { + struct plotters* plotters = malloc(sizeof(*plotters)); + if (plotters == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + plotters->gnuplot_w = _popen(GNUPLOT, "w"); + if (plotters->gnuplot_w == NULL) { + fprintf(stderr, "popen failed"); + thrd_exit(EXIT_FAILURE); + } + + fprintf(plotters->gnuplot_w, "set key autotitle columnheader\n"); + fprintf(plotters->gnuplot_w, "set xlabel 'Samples'\n"); + fprintf(plotters->gnuplot_w, "set ylabel 'ADC counts'\n"); + fprintf(plotters->gnuplot_w, "set grid\nset mouse\n"); + fprintf(plotters->gnuplot_w, "set key samplen 1 spacing 1\n"); + fflush(plotters->gnuplot_w); + + return plotters; +} + +static void close_plotters(struct plotters* plotters) { + _pclose(plotters->gnuplot_w); +} + +static int acq_thread(void* p) { + + int ret; + + struct acq_data* data = (struct acq_data*)p; + uint64_t ep_handle; + + ret = CAEN_FELib_GetHandle(data->dev_handle, "/endpoint/scope", &ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = configure_endpoint(ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // allocate stuff + struct event* evt = allocate_event(MAX_NUMBER_OF_SAMPLES, data->n_channels); + struct plotters* plt = open_plotters(); + + FILE* f_evt = NULL; + FILE* f_wave = NULL; + + if (EVT_FILE_ENABLED) { + f_evt = fopen(EVT_FILE_NAME, "w"); + if (f_evt == NULL) { + fprintf(stderr, "fopen failed"); + return EXIT_FAILURE; + } + } + + if (WAVE_FILE_ENABLED) { + f_wave = fopen(WAVE_FILE_NAME, "w"); + if (f_wave == NULL) { + fprintf(stderr, "fopen failed"); + return EXIT_FAILURE; + } + } + + // signal main thread + mtx_lock(&data->mtx); + data->ep_configured = true; + mtx_unlock(&data->mtx); + cnd_signal(&data->cnd); + + // wait main thread + mtx_lock(&data->mtx); + while (!data->acq_started) + cnd_wait(&data->cnd, &data->mtx); + mtx_unlock(&data->mtx); + + // acquisition loop + read_data_loop(plt, f_evt, f_wave, data, ep_handle, evt); + + // quit + if (f_evt != NULL) + fclose(f_evt); + if (f_wave != NULL) + fclose(f_wave); + close_plotters(plt); + free_event(evt); + + return EXIT_SUCCESS; +} + +int main(int argc, char* argv[]) { + + int ret; + + uint64_t dev_handle; + + printf("##########################################\n"); + printf("\tCAEN firmware Scope demo\n"); + printf("##########################################\n"); + + if (argc > 2) { + fputs("invalid arguments", stderr); + return EXIT_FAILURE; + } + + // select device + ret = connect_to_digitizer(&dev_handle, argc, argv); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = print_digitizer_details(dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + size_t n_channels; + ret = get_n_channels(dev_handle, &n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("Resetting...\t"); + + // reset + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/reset"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // start acquisition thread + struct acq_data data = { + .dev_handle = dev_handle, + .ep_configured = false, + .acq_started = false, + .n_channels = n_channels + }; + mtx_init(&data.mtx, mtx_plain); + cnd_init(&data.cnd); + thrd_t thrd; + ret = thrd_create(&thrd, &acq_thread, &data); + if (ret != thrd_success) { + fprintf(stderr, "thrd_create failed"); + return EXIT_FAILURE; + } + + printf("Configuring...\t"); + + ret = configure_digitizer(dev_handle, n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // wait configuration on acquisition thread + mtx_lock(&data.mtx); + while (!data.ep_configured) + cnd_wait(&data.cnd, &data.mtx); + mtx_unlock(&data.mtx); + + printf("done.\n"); + + printf("Starting...\t"); + + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/armacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/swstartacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // notify start to acquisition thread + mtx_lock(&data.mtx); + data.acq_started = true; + mtx_unlock(&data.mtx); + cnd_signal(&data.cnd); + + printf("##########################################\n"); + printf("Commands supported:\n"); + printf("\t[%c]\tsend manual trigger\n", COMMAND_TRIGGER); + printf("\t[%c]\tstop acquisition\n", COMMAND_STOP); + printf("\t[%c]\tplot next waveform\n", COMMAND_PLOT_WAVE); + printf("##########################################\n"); + + bool do_quit = false; + + do { + const int c = _getch(); + switch (c) { + case COMMAND_TRIGGER: { + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/sendswtrigger"); + if (ret != CAEN_FELib_Success) + print_last_error(); + break; + } + case COMMAND_STOP: { + do_quit = true; + break; + } + case COMMAND_PLOT_WAVE: { + mtx_lock(&data.mtx); + data.plot_next_wave = true; + mtx_unlock(&data.mtx); + break; + } + case '\n': { + break; + } + default: { + fprintf(stderr, "unknown command [%c]", c); + break; + } + } + } while (!do_quit); + + printf("\nStopping...\t"); + + ret = CAEN_FELib_SendCommand(dev_handle, "/cmd/disarmacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // wait the end of the acquisition + // that is going to finish just after the last event + int thrd_ret; + ret = thrd_join(thrd, &thrd_ret); + if (ret != thrd_success || thrd_ret != EXIT_SUCCESS) { + fprintf(stderr, "thrd_join error.\tret %d\tthrd_ret %d\n", ret, thrd_ret); + return EXIT_FAILURE; + } + mtx_destroy(&data.mtx); + cnd_destroy(&data.cnd); + + ret = CAEN_FELib_Close(dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("\nBye!\n"); + + return EXIT_SUCCESS; +} diff --git a/demo/caen-felib-demo-sync/Makefile b/demo/caen-felib-demo-sync/Makefile new file mode 100644 index 0000000..4de1d34 --- /dev/null +++ b/demo/caen-felib-demo-sync/Makefile @@ -0,0 +1,20 @@ +TARGET = caen-felib-demo-scope +CFLAGS = -std=gnu11 -O2 -g -Wall -pthread +LDFLAGS = -pthread +LDLIBS = -lpthread -lm -lCAEN_FELib + +.PHONY: default all clean + +default: $(TARGET) +all: default + +OBJECTS = main.o tlock_queue.c + +.PRECIOUS: $(TARGET) $(OBJECTS) + +$(TARGET): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $@ + +clean: + -rm -f *.o + -rm -f $(TARGET) diff --git a/demo/caen-felib-demo-sync/caen-felib-demo-sync.vcxproj b/demo/caen-felib-demo-sync/caen-felib-demo-sync.vcxproj new file mode 100644 index 0000000..481ca37 --- /dev/null +++ b/demo/caen-felib-demo-sync/caen-felib-demo-sync.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {3565CE9E-7A3F-49FC-9FC4-BE5BE373395B} + caenfelibdemosync + 10.0.16299.0 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + true + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + false + .\bin\$(Platform)\$(Configuration)\ + .\tmp\$(Platform)\$(Configuration)\ + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\include;%(AdditionalIncludeDirectories) + + + Console + true + true + false + $(ProgramW6432)\CAEN\Digitizers\CAEN FELib\lib\x86_64 + CAEN_FELib.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-sync/caen-felib-demo-sync.vcxproj.filters b/demo/caen-felib-demo-sync/caen-felib-demo-sync.vcxproj.filters new file mode 100644 index 0000000..68a9d4b --- /dev/null +++ b/demo/caen-felib-demo-sync/caen-felib-demo-sync.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/demo/caen-felib-demo-sync/main.c b/demo/caen-felib-demo-sync/main.c new file mode 100644 index 0000000..13f03e0 --- /dev/null +++ b/demo/caen-felib-demo-sync/main.c @@ -0,0 +1,1201 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +* SPDX-License-Identifier: MIT-0 +* +***************************************************************************//*! +* +* \file main.c +* \brief CAEN Open FPGA Digitzers Scope demo +* \author Giovanni Cerretani +* +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// windows or C11 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_THREADS__) +#include +#else +#include "c11threads.h" +#endif + +#include "tlock_queue.h" + +#include + +// Basic hardcoded configuration +#define COMMAND_TRIGGER 't' +#define COMMAND_STOP 'q' +#define COMMAND_NEXT_BOARD 'b' +#define COMMAND_INCR_DELAY '+' +#define COMMAND_DECR_DELAY '-' +#define MAX_NUMBER_OF_SAMPLES (1U << 12) +#define TIMEOUT_MS (100) +#define DATA_FORMAT " \ + [ \ + { \"name\" : \"TIMESTAMP\", \"type\" : \"U64\" }, \ + { \"name\" : \"TRIGGER_ID\", \"type\" : \"U32\" }, \ + { \"name\" : \"WAVEFORM\", \"type\" : \"U16\", \"dim\" : 2 }, \ + { \"name\" : \"WAVEFORM_SIZE\", \"type\" : \"SIZE_T\", \"dim\" : 1 }, \ + { \"name\" : \"EVENT_SIZE\", \"type\" : \"SIZE_T\" } \ + ] \ +" + +// CFD settings +#define CFD_FRACTION 0.25 +#define CFD_DELAY 32 // samples +#define CFD_ARMED_THR -100. +#define CFD_PULSE_POLARITY false // true if positive, false if negative + +// Utilities +#define ARRAY_SIZE(X) (sizeof(X)/sizeof((X)[0])) + +#ifdef _WIN32 // Windows +#include +#define GNUPLOT "pgnuplot.exe" +#else // Linux +#include +#include +#define GNUPLOT "gnuplot" +#define _popen(command, type) popen(command, type) +#define _pclose(command) pclose(command) +// Linux replacement for non standard _getch +static int _getch() { + struct termios oldattr; + if (tcgetattr(STDIN_FILENO, &oldattr) == -1) perror(NULL); + struct termios newattr = oldattr; + newattr.c_lflag &= ~(ICANON | ECHO); + if (tcsetattr(STDIN_FILENO, TCSANOW, &newattr) == -1) perror(NULL); + const int ch = getchar(); + if (tcsetattr(STDIN_FILENO, TCSANOW, &oldattr) == -1) perror(NULL); + return ch; +} +#endif + +static unsigned long long value_to_ull(const char* value) { + char* value_end; + const unsigned long long ret = strtoull(value, &value_end, 0); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtoull error\n"); + return ret; +} + +static double value_to_d(const char* value) { + char* value_end; + const double ret = strtod(value, &value_end); + if (value == value_end || errno == ERANGE) + fprintf(stderr, "strtod error\n"); + return ret; +} + +static int print_last_error(void) { + char msg[1024]; + int ec = CAEN_FELib_GetLastError(msg); + if (ec != CAEN_FELib_Success) { + fprintf(stderr, "%s failed\n", __func__); + return ec; + } + fprintf(stderr, "last error: %s\n", msg); + return ec; +} + +static int get_n_channels(uint64_t dev_handle, size_t* n_channels) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + *n_channels = (size_t)value_to_ull(value); + return ret; +} + +static int get_sampling_rate(uint64_t dev_handle, double* sampling_rate) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_SamplRate", value); + if (ret != CAEN_FELib_Success) return ret; + *sampling_rate = value_to_d(value); + return ret; +} + +static int print_digitizer_details(uint64_t dev_handle) { + int ret; + char value[256]; + ret = CAEN_FELib_GetValue(dev_handle, "/par/ModelName", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Model name:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/SerialNum", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Serial number:\t%s\n", value); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_Nbit", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC bits:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/NumCh", value); + if (ret != CAEN_FELib_Success) return ret; + printf("Channels:\t%llu\n", value_to_ull(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/ADC_SamplRate", value); + if (ret != CAEN_FELib_Success) return ret; + printf("ADC rate:\t%f Msps\n", value_to_d(value)); + ret = CAEN_FELib_GetValue(dev_handle, "/par/cupver", value); + if (ret != CAEN_FELib_Success) return ret; + printf("CUP version:\t%s\n", value); + return ret; +} + +static int configure_digitizer(uint64_t dev_handle, size_t n_channels) { + + int ret; + char value[256]; + char par_name[256]; + + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ChEnable", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "True"); + if (ret != CAEN_FELib_Success) return ret; + + const unsigned int record_length = MAX_NUMBER_OF_SAMPLES; // in samples + snprintf(value, sizeof(value), "%u", record_length); + ret = CAEN_FELib_SetValue(dev_handle, "/par/RecordLengthS", value); + if (ret != CAEN_FELib_Success) return ret; + + const unsigned int pre_trigger = 100; // in samples + snprintf(value, sizeof(value), "%u", pre_trigger); + ret = CAEN_FELib_SetValue(dev_handle, "/par/PreTriggerS", value); + if (ret != CAEN_FELib_Success) return ret; + + ret = CAEN_FELib_SetValue(dev_handle, "/par/AcqTriggerSource", "SwTrg | ITLA"); + if (ret != CAEN_FELib_Success) return ret; + + const double pulse_period = 100e3; // in nsec + snprintf(value, sizeof(value), "%f", pulse_period); + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulsePeriod", value); + if (ret != CAEN_FELib_Success) return ret; + + const unsigned int pulse_width = 128; // in nsec + snprintf(value, sizeof(value), "%u", pulse_width); + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulseWidth", value); + if (ret != CAEN_FELib_Success) return ret; + + const unsigned int pulse_low = 0; // in ADC counts + snprintf(value, sizeof(value), "%u", pulse_low); + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulseLowLevel", value); + if (ret != CAEN_FELib_Success) return ret; + + const unsigned int pulse_high = 10000; // in ADC counts + snprintf(value, sizeof(value), "%u", pulse_high); + ret = CAEN_FELib_SetValue(dev_handle, "/par/TestPulseHighLevel", value); + if (ret != CAEN_FELib_Success) return ret; + + const double dc_offset = 50.; // in percent + snprintf(value, sizeof(value), "%f", dc_offset); + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/DCOffset", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, value); + if (ret != CAEN_FELib_Success) return ret; + + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/ITLConnect", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "ITLA"); + if (ret != CAEN_FELib_Success) return ret; + + const int trigger_thr = 9000; // in ADC counts + snprintf(value, sizeof(value), "%d", trigger_thr); + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/TriggerThr", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, value); + if (ret != CAEN_FELib_Success) return ret; + + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/TriggerThrMode", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "Absolute"); + if (ret != CAEN_FELib_Success) return ret; + + const unsigned int samples_over_threshold = 16; // in samples + snprintf(value, sizeof(value), "%u", samples_over_threshold); + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/SamplesOverThreshold", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, value); + if (ret != CAEN_FELib_Success) return ret; + + snprintf(par_name, sizeof(par_name), "/ch/0..%zu/par/SelfTriggerEdge", n_channels - 1); + ret = CAEN_FELib_SetValue(dev_handle, par_name, "Rise"); + if (ret != CAEN_FELib_Success) return ret; + + return ret; + +} + +static int get_run_delay(size_t board_id, size_t n_boards) { + + const bool first_board = (board_id == 0); + const size_t board_id_from_last = n_boards - board_id - 1; + + // Run delay in clock cycles: 2 cycles per board + int run_delay_clk = 2 * (int)board_id_from_last; + + // additional 4 cycles in the first board + if (first_board) + run_delay_clk += 4; + + const int run_delay_ns = run_delay_clk * 8; // clock period is 8 ns for all boards + + return run_delay_ns; + +} + +static int get_clock_out_delay(size_t board_id, size_t n_boards) { + + const bool first_board = (board_id == 0); + const bool last_board = (board_id == n_boards - 1); + + const int clock_out_delay_ps = last_board ? 0 : (first_board ? -2148 : -3111); + + return clock_out_delay_ps; + +} + +static int configure_sync(uint64_t dev_handle, size_t board_id, size_t n_boards) { + + int ret; + char run_delay_value[256]; + char clock_out_delay_value[256]; + + const bool first_board = (board_id == 0); + const bool last_board = (board_id == n_boards - 1); + + const int run_delay = get_run_delay(board_id, n_boards); + snprintf(run_delay_value, sizeof(run_delay_value), "%d", run_delay); + + const int clock_out_delay = get_clock_out_delay(board_id, n_boards); + snprintf(clock_out_delay_value, sizeof(clock_out_delay_value), "%d", clock_out_delay); + + ret = CAEN_FELib_SetValue(dev_handle, "/par/ClockSource", first_board ? "Internal" : "FPClkIn"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/SyncOutMode", last_board ? "Disabled" : (first_board ? "Run" : "SyncIn")); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/StartSource", first_board ? "SWcmd" : "EncodedClkIn"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/EnClockOutFP", last_board ? "False" : "True"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/RunDelay", run_delay_value); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/VolatileClockOutDelay", clock_out_delay_value); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(dev_handle, "/par/EnAutoDisarmAcq", "True"); + if (ret != CAEN_FELib_Success) return ret; + + // 62.5 MHz clock on TrgOut for delay measurement + ret = CAEN_FELib_SetValue(dev_handle, "/par/TrgOutMode", "RefClk"); + if (ret != CAEN_FELib_Success) return ret; + + // TestPulse wave on DACOut for debug + ret = CAEN_FELib_SetValue(dev_handle, "/par/DACOutMode", "Square"); + if (ret != CAEN_FELib_Success) return ret; + + return ret; + +} + +static int configure_endpoint(uint64_t ep_handle) { + int ret; + // conigure endpoint + uint64_t ep_folder_handle; + ret = CAEN_FELib_GetParentHandle(ep_handle, NULL, &ep_folder_handle); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetValue(ep_folder_handle, "/par/activeendpoint", "scope"); + if (ret != CAEN_FELib_Success) return ret; + ret = CAEN_FELib_SetReadDataFormat(ep_handle, DATA_FORMAT); + if (ret != CAEN_FELib_Success) return ret; + return ret; +} + +struct counters { + size_t total_size; + size_t n_events; + time_t t_begin; +}; + +/* + * Allocated once per board, reused for each call + * to CAEN_FELib_ReadData. Fields to be shared + * with the data_thread will be copied to an instance + * of struct processed_event before reading the + * next event. + */ +struct event { + // costants + size_t board_id; + size_t n_channels; + double adc_sampling_period_ns; + + // native fields + uint64_t timestamp; + uint32_t trigger_id; + size_t event_size; + uint16_t** waveform; + size_t* n_samples; + size_t* n_allocated_samples; +}; + +/* + * Almost same of struct event but containing only those + * fields that we want to share with the data_thread. + * It is allocated for each received event in the acq_thread + * and freed in the data_thread once the information has + * been processed. + */ +struct processed_event { + // costants + size_t board_id; + size_t n_channels; + double adc_sampling_period_ns; + + // event fields + uint64_t timestamp; + uint32_t trigger_id; + size_t event_size; + double* zero_crossing_ns; +}; + +struct shared_data { + size_t n_boards; + mtx_t* acq_mtx; + cnd_t* acq_cnd; + bool* acq_started; + tlock_queue_t* evt_queue; +}; + +struct acq_data { + uint64_t dev_handle; + size_t board_id; + mtx_t mtx; + cnd_t cnd; + bool ep_configured; + struct shared_data shared_data; +}; + +static void print_stats(double t, size_t n_events, double rate) { + printf("\x1b[1K\rTime (s): %.1f\tEvents: %zu\tReadout rate (MB/s): %f", t, n_events, rate); + fflush(stdout); +} + +static double counters_dt(struct counters* c, time_t t) { + return difftime(t, c->t_begin); +} + +static double counters_rate(struct counters* c, time_t t) { + return c->total_size / counters_dt(c, t) / (1024. * 1024.); // MB/s +} + +static void counters_increment(struct counters* c, size_t size) { + c->total_size += size; + ++c->n_events; +} + +static void counters_reset(struct counters* c, time_t t) { + c->total_size = 0; + c->n_events = 0; + c->t_begin = t; +} + +static bool enqueue_processed_event(struct processed_event* evt, tlock_queue_t* evt_queue) { + + const int tlock_ret = tlock_push(evt_queue, evt); + if (tlock_ret != TLOCK_OK) { + fprintf(stderr, "tlock_push failed\n"); + free(evt); + return false; + } + + return true; + +} + +/* + * ADD YOUR CODE HERE! + * + * Example function that extract some information from + * the event generated by the digitizer. + * + * For example, here we implement a CFD to fill + * evt->zero_crossing_ns for each channel. If not found, + * the value is left set to nan("zc"). + */ +static struct processed_event* generate_processed_event(const struct event* evt) { + + // Allocate event to be passed to data thread, free called there + struct processed_event* processed_evt = malloc(sizeof(*processed_evt)); + if (processed_evt == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + + processed_evt->zero_crossing_ns = malloc(evt->n_channels * sizeof(*processed_evt->zero_crossing_ns)); + if (processed_evt->zero_crossing_ns == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + + // Copy native fields + processed_evt->board_id = evt->board_id; + processed_evt->n_channels = evt->n_channels; + processed_evt->adc_sampling_period_ns = evt->adc_sampling_period_ns; + processed_evt->timestamp = evt->timestamp; + processed_evt->trigger_id = evt->trigger_id; + processed_evt->event_size = evt->event_size; + + // Get maximum n_samples to allocate utility buffers once + + size_t max_n_samples = 0; + + for (size_t ch = 0; ch < evt->n_channels; ++ch) { + + // Initialize also zero_crossing on this loop + processed_evt->zero_crossing_ns[ch] = nan("zc"); + + if (evt->n_samples[ch] > max_n_samples) + max_n_samples = evt->n_samples[ch]; + + } + + if (max_n_samples == 0) + return processed_evt; + + // Allocate buffers for smoothed waveform and discriminator signal + + double* const waveform_smoothed = malloc(max_n_samples * sizeof(*waveform_smoothed)); + if (waveform_smoothed == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + + double* const discriminator = malloc(max_n_samples * sizeof(*discriminator)); + if (discriminator == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + + // Calculate CFD for all channels + + for (size_t ch = 0; ch < evt->n_channels; ++ch) { + + const size_t n_samples = evt->n_samples[ch]; + if (n_samples == 0) + continue; + + const uint16_t* waveform = evt->waveform[ch]; + + // Calculate baseline and fill smoothed waveform + + const size_t n_baseline_samples = 16; // hardcoded + assert(n_samples > n_baseline_samples); + + double baseline_acc = 0.; + for (size_t j = 0; j < n_baseline_samples; ++j) + baseline_acc += waveform[j]; + + const double baseline = baseline_acc / n_baseline_samples; + + for (size_t i = 0; i < n_samples; ++i) { + // todo add smooting + waveform_smoothed[i] = waveform[i] - baseline; + } + + // Calculate CFD + + // constants, hardcoded + const double cfd_fraction = CFD_FRACTION; + const size_t cfd_delay = CFD_DELAY; // samples + const double cfr_armed_thr = CFD_ARMED_THR; + const bool pulse_polarity_positive = CFD_PULSE_POLARITY; + + assert(cfd_fraction > 0.); + assert(cfr_armed_thr < 0.); + + // discriminator is intended for negative pulses; if positive invert it + const double pulse_sign = pulse_polarity_positive ? -1. : 1.; + + bool cfd_armed = false; + + for (size_t i = 0; i < n_samples; ++i) { + + const double waveform_attenuated = cfd_fraction * waveform_smoothed[i]; + const double waveform_delayed = (i < cfd_delay) ? 0. : waveform_smoothed[i - cfd_delay]; + + discriminator[i] = pulse_sign * (waveform_attenuated - waveform_delayed); + + // arm cfd on a negative threshold + if (!cfd_armed && (discriminator[i] < cfr_armed_thr)) + cfd_armed = true; + + // if armed, detect zero crossing + if (cfd_armed && (discriminator[i] >= 0.)) { + + // consistency checks + assert(i > 0); // cannot occour on first sample + + // zero crossing settings + const size_t zc_i = i - 1; + const double zc_negative = discriminator[i - 1]; + const double zc_positive = discriminator[i]; + + // consistency checks + assert(zc_negative < 0.); // discriminator was negative previous sample + assert(zc_positive >= 0.); // implied by if-condition + assert(zc_negative != zc_positive); + + // calculate fine zero crossing by linear interpolation + const double zc_linear_interpolation = zc_negative / (zc_negative - zc_positive); + const double zc_fine = zc_i + zc_linear_interpolation; + + // consistency checks + assert(zc_linear_interpolation > 0.); // implied by previous assertions + assert(zc_fine >= zc_i); // implied by previous assertions + + // set zero crossing to the event + processed_evt->zero_crossing_ns[ch] = evt->adc_sampling_period_ns * zc_fine; + + // interrupt the search at the first zero crossing + break; + + } + + } + + } + + free(discriminator); + free(waveform_smoothed); + + return processed_evt; + +} + +static struct processed_event* generate_stop_event() { + + // Allocate event to be passed to data thread, free called there + struct processed_event* processed_evt = malloc(sizeof(*processed_evt)); + if (processed_evt == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + + processed_evt->zero_crossing_ns = NULL; + processed_evt->event_size = 0; // fake event + + return processed_evt; + +} + +static void read_data_loop(uint64_t ep_handle, struct event* evt, tlock_queue_t* evt_queue) { + + for (;;) { + + const int ret = CAEN_FELib_ReadData(ep_handle, TIMEOUT_MS, + &evt->timestamp, + &evt->trigger_id, + evt->waveform, + evt->n_samples, + &evt->event_size + ); + switch (ret) { + case CAEN_FELib_Success: { + + // extract custom information from the native event + struct processed_event* processed_evt = generate_processed_event(evt); + + // pass event to data thread + if (!enqueue_processed_event(processed_evt, evt_queue)) { + fprintf(stderr, "enqueue_processed_event failed\n"); + } + + break; + } + case CAEN_FELib_Timeout: + break; + case CAEN_FELib_Stop: + printf("\nStop received.\n"); + + struct processed_event* stop_evt = generate_stop_event(); + + // signal end of run with fake event to data thread + if (!enqueue_processed_event(stop_evt, evt_queue)) { + fprintf(stderr, "enqueue_processed_event failed\n"); + } + + return; + default: + print_last_error(); + break; + } + } +} + +static struct event* allocate_event(size_t n_samples, size_t n_channels) { + struct event* const evt = malloc(sizeof(*evt)); + if (evt == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->n_channels = n_channels; + evt->n_samples = malloc(evt->n_channels * sizeof(*evt->n_samples)); + if (evt->n_samples == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->n_allocated_samples = malloc(evt->n_channels * sizeof(*evt->n_allocated_samples)); + if (evt->n_allocated_samples == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + evt->waveform = malloc(evt->n_channels * sizeof(*evt->waveform)); + if (evt->waveform == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + for (size_t i = 0; i < evt->n_channels; ++i) { + evt->n_allocated_samples[i] = n_samples; + evt->waveform[i] = malloc(evt->n_allocated_samples[i] * sizeof(*evt->waveform[i])); + if (evt->waveform[i] == NULL) { + fprintf(stderr, "malloc failed"); + thrd_exit(EXIT_FAILURE); + } + } + return evt; +} + +static void free_event(struct event* evt) { + free(evt->n_samples); + free(evt->n_allocated_samples); + for (size_t i = 0; i < evt->n_channels; ++i) + free(evt->waveform[i]); + free(evt); +} + +static int acq_thread(void* p) { + + int ret; + + struct acq_data* data = (struct acq_data*)p; + uint64_t ep_handle; + + size_t n_channels; + ret = get_n_channels(data->dev_handle, &n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + double sampling_rate; // in MHz + ret = get_sampling_rate(data->dev_handle, &sampling_rate); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // reset + ret = CAEN_FELib_SendCommand(data->dev_handle, "/cmd/reset"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // configure board + ret = configure_digitizer(data->dev_handle, n_channels); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = configure_sync(data->dev_handle, data->board_id, data->shared_data.n_boards); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // configure endpoint + ret = CAEN_FELib_GetHandle(data->dev_handle, "/endpoint/scope", &ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = configure_endpoint(ep_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // allocate stuff + struct event* evt = allocate_event(MAX_NUMBER_OF_SAMPLES, n_channels); + + // initialize event costants + evt->board_id = data->board_id; + evt->adc_sampling_period_ns = 1000. / sampling_rate; + + // arm acquisition + ret = CAEN_FELib_SendCommand(data->dev_handle, "/cmd/armacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // signal main thread + mtx_lock(&data->mtx); + data->ep_configured = true; + mtx_unlock(&data->mtx); + cnd_signal(&data->cnd); + + // wait main thread + mtx_lock(data->shared_data.acq_mtx); + while (!*data->shared_data.acq_started) + cnd_wait(data->shared_data.acq_cnd, data->shared_data.acq_mtx); + mtx_unlock(data->shared_data.acq_mtx); + + // acquisition loop + read_data_loop(ep_handle, evt, data->shared_data.evt_queue); + + free_event(evt); + + return EXIT_SUCCESS; +} + +// inspired to to C++ std::vector +struct evt_list { + struct processed_event** data; + size_t size; + size_t capacity; +}; + +static void add_evt_to_list(struct evt_list* evt_list, struct processed_event* evt) { + + // local copy of evt_list to reduce dereferences on this function. evt_list is updated on exit. + struct evt_list local_evt_list = *evt_list; + + // adjust capacity if required + if (local_evt_list.capacity <= local_evt_list.size) { + assert(local_evt_list.capacity != 0); + const size_t new_capacity = local_evt_list.capacity * 2; // double capacity + struct processed_event** new_data = realloc(local_evt_list.data, sizeof(*local_evt_list.data) * new_capacity); + if (new_data == NULL) { + fprintf(stderr, "realloc failed"); + thrd_exit(EXIT_FAILURE); + } + local_evt_list.data = new_data; + local_evt_list.capacity = new_capacity; + } + assert(local_evt_list.capacity > local_evt_list.size); + + // get evt timestamp + const uint64_t evt_timestamp = evt->timestamp; + + // add new event in sorted list (current elements are already sorted, qsort would be overkilling) + size_t evt_pos = local_evt_list.size; + for (; evt_pos != 0; --evt_pos) + if (local_evt_list.data[evt_pos - 1]->timestamp < evt_timestamp) + break; + const size_t n_evt_moved = local_evt_list.size - evt_pos; + memmove(local_evt_list.data + evt_pos + 1, local_evt_list.data + evt_pos, n_evt_moved * sizeof(*local_evt_list.data)); + local_evt_list.data[evt_pos] = evt; + ++local_evt_list.size; + + // update evt_list + *evt_list = local_evt_list; + +} + +static void process_evt_list(struct evt_list* evt_list) { + + const uint64_t timestamp_window = 125000000; // 1 s + + // local copy of evt_list to reduce dereferences on this function. evt_list is updated on exit. + struct evt_list local_evt_list = *evt_list; + + // nothing to do if there is only an event + if (local_evt_list.size == 1) + return; + + /* + * ADD YOUR CODE HERE! + * + * Process the event list here! + */ + + // get most recent timestamp + const uint64_t last_timestamp = local_evt_list.data[local_evt_list.size - 1]->timestamp; + + // free data outside current window + size_t i = 0; // counter of removed events + for (; i < local_evt_list.size; ++i) { + if (last_timestamp - local_evt_list.data[i]->timestamp > timestamp_window) { + + /* + * ADD YOUR CODE HERE! + * + * Process data just before removing old events + * + * Here we do not search for coincidences between board, + * we just fill an histogram with dt between channels of a specific board. + */ + + free(local_evt_list.data[i]->zero_crossing_ns); + free(local_evt_list.data[i]); + + } else { + break; // events are sorted: next events are more recents + } + } + + // remove removed items and update evt_list + if (i != 0) { + local_evt_list.size -= i; + memmove(local_evt_list.data, local_evt_list.data + i, local_evt_list.size * sizeof(*local_evt_list.data)); + *evt_list = local_evt_list; + } + +} + +static int data_thread(void* p) { + + struct shared_data* data = (struct shared_data*)p; + + size_t missing_stop_events = data->n_boards; + + struct counters total; + struct counters interval; + + counters_reset(&total, time(NULL)); + counters_reset(&interval, total.t_begin); + + const size_t initial_capacity = 1; + struct evt_list evt_list = { + .data = malloc(sizeof(*evt_list.data) * initial_capacity), + .size = 0, + .capacity = initial_capacity + }; + + if (evt_list.data == NULL) { + fprintf(stderr, "malloc failed"); + return EXIT_FAILURE; + } + + // wait main thread + mtx_lock(data->acq_mtx); + while (!*data->acq_started) + cnd_wait(data->acq_cnd, data->acq_mtx); + mtx_unlock(data->acq_mtx); + + while (missing_stop_events != 0) { + + const time_t current_time = time(NULL); + const double dt = counters_dt(&interval, current_time); + if (dt >= 1.) { + // print stats + print_stats(counters_dt(&total, current_time), total.n_events, counters_rate(&interval, current_time)); + counters_reset(&interval, current_time); + } + + struct processed_event* evt = tlock_pop(data->evt_queue); + if (evt == NULL) { + // wait 100 ms + thrd_sleep(&(struct timespec){.tv_nsec=100000000}, NULL); + continue; + } + + if (evt->event_size == 0) { + // fake event to signal end of run + --missing_stop_events; + free(evt); + continue; + } + + counters_increment(&total, evt->event_size); + counters_increment(&interval, evt->event_size); + + add_evt_to_list(&evt_list, evt); + + process_evt_list(&evt_list); + + } + + // free remaining events + for (size_t i = 0; i < evt_list.size; ++i) + free(evt_list.data[i]); + free(evt_list.data); + + return EXIT_SUCCESS; + +} + +static int increment_clock_out_delay(uint64_t dev_handle, int n_steps) { + + int ret; + char value[256]; + + const char par_name[] = "/par/VolatileClockOutDelay"; + const char incr_attribute_name[] = "/par/VolatileClockOutDelay/increment"; + + // get increment from parameter attribute + ret = CAEN_FELib_GetValue(dev_handle, incr_attribute_name, value); + if (ret != CAEN_FELib_Success) return ret; + const double incr = value_to_d(value); + // get current value + ret = CAEN_FELib_GetValue(dev_handle, par_name, value); + if (ret != CAEN_FELib_Success) return ret; + const double current_clock_out = value_to_d(value); + // set new value + const double new_clock_out = current_clock_out + (n_steps * incr); + snprintf(value, sizeof(value), "%f", new_clock_out); + ret = CAEN_FELib_SetValue(dev_handle, par_name, value); + if (ret != CAEN_FELib_Success) return ret; + + return CAEN_FELib_Success; + +} + +int main(int argc, char* argv[]) { + + int ret; + + printf("##########################################\n"); + printf("\tCAEN firmware Sync demo\n"); + printf("##########################################\n"); + + if (argc == 1) { + fputs("invalid arguments", stderr); + return EXIT_FAILURE; + } + + const size_t n_boards = argc - 1; + + struct acq_data* const board_data = malloc(sizeof(*board_data) * n_boards); + if (board_data == NULL) { + fprintf(stderr, "malloc failed\n"); + return EXIT_FAILURE; + } + + thrd_t* const thrds = malloc(sizeof(*thrds) * n_boards); + if (thrds == NULL) { + fprintf(stderr, "malloc failed\n"); + return EXIT_FAILURE; + } + + // initialize variabled shared by threads + bool acq_started = false; + mtx_t acq_mtx; + cnd_t acq_cnd; + mtx_init(&acq_mtx, mtx_plain); + cnd_init(&acq_cnd); + tlock_queue_t* const evt_queue = tlock_init(); + if (evt_queue == NULL) { + fprintf(stderr, "tlock_init failed\n"); + return EXIT_FAILURE; + } + + struct shared_data shared_data = { + .n_boards = n_boards, + .acq_mtx = &acq_mtx, + .acq_cnd = &acq_cnd, + .acq_started = &acq_started, + .evt_queue = evt_queue + }; + + // open devices + for (size_t i = 0; i < n_boards; ++i) { + + struct acq_data* data = &board_data[i]; + + // CAEN_FELib_Open is not thread safe + const char* path = argv[i + 1]; + printf("device path: %s\n", path); + + ret = CAEN_FELib_Open(path, &data->dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + // initialize other fields + data->board_id = i; + mtx_init(&data->mtx, mtx_plain); + cnd_init(&data->cnd); + data->ep_configured = false; + + // copy shared_data + data->shared_data = shared_data; + + ret = print_digitizer_details(data->dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + ret = thrd_create(thrds + i, acq_thread, data); + if (ret != thrd_success) { + fprintf(stderr, "thrd_create failed"); + return EXIT_FAILURE; + } + } + + printf("Configuring...\t"); + + // wait configuration on acquisition thread + for (size_t i = 0; i < n_boards; ++i) { + struct acq_data* data = &board_data[i]; + mtx_lock(&data->mtx); + while (!data->ep_configured) + cnd_wait(&data->cnd, &data->mtx); + mtx_unlock(&data->mtx); + } + + printf("done.\n"); + + printf("Starting...\t"); + + // launch data collection thread + thrd_t data_thrd; + ret = thrd_create(&data_thrd, &data_thread, &shared_data); + if (ret != thrd_success) { + fprintf(stderr, "thrd_create failed"); + return EXIT_FAILURE; + } + + // send software start on first board only + ret = CAEN_FELib_SendCommand(board_data[0].dev_handle, "/cmd/swstartacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // notify start to acquisition thread + mtx_lock(&acq_mtx); + acq_started = true; + mtx_unlock(&acq_mtx); + cnd_broadcast(&acq_cnd); + + printf("##########################################\n"); + printf("Commands supported:\n"); + printf("\t[%c]\tselect next board\n", COMMAND_NEXT_BOARD); + printf("\t[%c]\tincrement clock out delay of current board by minimum step\n", COMMAND_INCR_DELAY); + printf("\t[%c]\tdecrement clock out delay of current board by minimum step\n", COMMAND_DECR_DELAY); + printf("\t[%c]\tsend manual trigger to current board\n", COMMAND_TRIGGER); + printf("\t[%c]\tstop acquisition\n", COMMAND_STOP); + printf("##########################################\n"); + + bool do_quit = false; + size_t current_board = 0; + + do { + const int c = _getch(); + switch (c) { + case COMMAND_TRIGGER: { + ret = CAEN_FELib_SendCommand(board_data[current_board].dev_handle, "/cmd/sendswtrigger"); + if (ret != CAEN_FELib_Success) + print_last_error(); + break; + } + case COMMAND_STOP: { + do_quit = true; + break; + } + case COMMAND_NEXT_BOARD: { + if (++current_board == n_boards) + current_board = 0; + break; + } + case COMMAND_INCR_DELAY: { + ret = increment_clock_out_delay(board_data[current_board].dev_handle, 1); + if (ret != CAEN_FELib_Success) + print_last_error(); + break; + } + case COMMAND_DECR_DELAY: { + ret = increment_clock_out_delay(board_data[current_board].dev_handle, -1); + if (ret != CAEN_FELib_Success) + print_last_error(); + break; + } + case '\n': { + break; + } + default: { + fprintf(stderr, "unknown command [%c]", c); + break; + } + } + } while (!do_quit); + + printf("\nStopping...\t"); + + ret = CAEN_FELib_SendCommand(board_data[0].dev_handle, "/cmd/swstopacquisition"); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + + printf("done.\n"); + + // wait the end of the acquisition + // that is going to finish just after the last event + for (size_t i = 0; i < n_boards; ++i) { + struct acq_data* data = &board_data[i]; + int thrd_ret; + ret = thrd_join(thrds[i], &thrd_ret); + if (ret != thrd_success || thrd_ret != EXIT_SUCCESS) { + fprintf(stderr, "thrd_join error.\tret %d\tthrd_ret %d\n", ret, thrd_ret); + return EXIT_FAILURE; + } + mtx_destroy(&data->mtx); + cnd_destroy(&data->cnd); + + ret = CAEN_FELib_Close(data->dev_handle); + if (ret != CAEN_FELib_Success) { + print_last_error(); + return EXIT_FAILURE; + } + } + + int data_thrd_ret; + + ret = thrd_join(data_thrd, &data_thrd_ret); + if (ret != thrd_success || data_thrd_ret != EXIT_SUCCESS) { + fprintf(stderr, "thrd_join error.\tret %d\tdata_thrd_ret %d\n", ret, data_thrd_ret); + return EXIT_FAILURE; + } + + mtx_destroy(&acq_mtx); + cnd_destroy(&acq_cnd); + tlock_free(evt_queue); + + printf("\nBye!\n"); + + return EXIT_SUCCESS; +} diff --git a/demo/caen-felib-demo-sync/tlock_queue.c b/demo/caen-felib-demo-sync/tlock_queue.c new file mode 100644 index 0000000..e41bcf3 --- /dev/null +++ b/demo/caen-felib-demo-sync/tlock_queue.c @@ -0,0 +1,173 @@ +#include +#include + +#ifndef __STDC_NO_THREADS__ + +#include "tlock_queue.h" + +/* Helper function to allocate and initialize a queue node */ +#ifdef __GNUC__ +__attribute__ ((malloc)) +#endif +inline static _tlock_node_t* _tlock_node_init(void* value) { + _tlock_node_t* node; + + if ( (node = malloc(sizeof(_tlock_node_t))) == NULL ) { + return NULL; + } + + node->value = value; + node->next = NULL; + + return node; +} + +/* Helper function to free a queue node */ +inline static void _tlock_node_free(_tlock_node_t* node) { + free(node); +} + +/* Allocates and initializes queue */ +#ifdef __GNUC__ +__attribute__ ((malloc)) +#endif +tlock_queue_t* tlock_init() { + tlock_queue_t* queue; + _tlock_node_t* dummy; + + /* Allocate queue */ + if ( (queue = malloc(sizeof(tlock_queue_t))) == NULL ) + return NULL; + + /* Allocate mutexes */ + if ( (queue->first_mutex = malloc(sizeof(mtx_t))) == NULL ) { + free(queue); + return NULL; + } + if ( (queue->last_mutex = malloc(sizeof(mtx_t))) == NULL ) { + free(queue->first_mutex); + free(queue); + return NULL; + } + + /* Initialize mutexes */ + if (mtx_init(queue->first_mutex, mtx_plain) != thrd_success || mtx_init(queue->last_mutex, mtx_plain) != thrd_success) { + tlock_free(queue); + return NULL; + } + + /* Allocate dummy node */ + if ( (dummy = _tlock_node_init(NULL)) == NULL ) { + tlock_free(queue); + return NULL; + } + + /* Initialize ends of queue */ + queue->first = queue->last = dummy; + + return queue; +} + +/* Frees queue resources. Assumes the queue is depleted */ +void tlock_free(tlock_queue_t* queue) { + + if (queue == NULL) { + return; + } + + /* Free the dummy node */ + if (queue->first != NULL) { + free(queue->first); + } + + /* Destroy and free mutexes */ + if (queue->first_mutex != NULL ){ + mtx_destroy(queue->first_mutex); + free(queue->first_mutex); + } + if (queue->last_mutex != NULL) { + mtx_destroy(queue->last_mutex); + free(queue->last_mutex); + } + + free(queue); +} + +/* Push at the end of the queue */ +#ifdef __GNUC__ +__attribute__ ((warn_unused_result)) +#endif +int tlock_push(tlock_queue_t* __restrict queue, void* __restrict new_element) { + _tlock_node_t* node; + + /* Prepare new node */ + if ( (node = _tlock_node_init(new_element)) == NULL ) { + return TLOCK_ERROR; + } + + /* Add to queue with lock */ + mtx_lock(queue->last_mutex); + queue->last->next = node; + queue->last = node; + mtx_unlock(queue->last_mutex); + + return TLOCK_OK; +} + +/* Pop from beginning of queue */ +void* tlock_pop(tlock_queue_t* queue) { + _tlock_node_t* node; /* Node to be removed */ + _tlock_node_t* new_header; /* Node that will become the first in the queue */ + void* return_value; /* Data to be retrieved */ + + mtx_lock(queue->first_mutex); + + node = queue->first; + new_header = queue->first->next; + + /* Queue is empty */ + if (new_header == NULL) { + mtx_unlock(queue->first_mutex); + return NULL; + } + + /* Queue not empty: retrieve data and rewire */ + return_value = new_header->value; + queue->first = new_header; + + mtx_unlock(queue->first_mutex); + + /* Free removed node and return */ + _tlock_node_free(node); + return return_value; +} + +/* + * Retrieves the minimum number of elements in the queue at the time of function call. The number + * can be bigger if threads are pushing to the queue concurrently. + */ +size_t tlock_min_size(const tlock_queue_t* queue) { + register size_t counter = 0; + _tlock_node_t* node; + + mtx_lock(queue->first_mutex); + + /* Get first element if queue is not empty */ + if ( (node = queue->first->next) != NULL ) { + ++counter; + } + + /* Count the rest of elements */ + while (node != NULL && node->next != NULL) { + ++counter; + node = node->next; + } + + mtx_unlock(queue->first_mutex); + + return counter; +} + +#else + #pragma message ( "No C11 thread support" ) +#endif diff --git a/demo/caen-felib-demo-sync/tlock_queue.h b/demo/caen-felib-demo-sync/tlock_queue.h new file mode 100644 index 0000000..46d6615 --- /dev/null +++ b/demo/caen-felib-demo-sync/tlock_queue.h @@ -0,0 +1,63 @@ +#ifndef _TLOCK_QUEUE_H +#define _TLOCK_QUEUE_H + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_THREADS__) +#include +#else +#include "c11threads.h" +#endif + +/* Possible return values */ +enum { + TLOCK_OK, + TLOCK_ERROR +}; + +/* Queue node. For internal use only, the user should not interact with this struct. */ +typedef struct { + void* value; + void* next; +} _tlock_node_t; + +/* + * Two lock queue data structure. The user should not interact directly with it, but rather through + * the available functions. + */ +typedef struct { + _tlock_node_t* first; + _tlock_node_t* last; + mtx_t* first_mutex; + mtx_t* last_mutex; +} tlock_queue_t; + +/* Returns a pointer to an allocated struct for the synchronized queue or NULL on failure. */ +tlock_queue_t* tlock_init(); + +/* + * Frees the queue struct. It assumes that the queue is depleted, and it will not manage allocated + * elements inside of it. + */ +void tlock_free(tlock_queue_t*); + +/* + * Add element to queue. The client is responsible for freeing elementsput into the queue + * afterwards. + * Returns TLOCK_OK on success or TLOCK_ERROR on failure. + */ +int tlock_push(tlock_queue_t* __restrict, void* __restrict); + +/* + * Retrieve element and remove it from the queue. + * Returns a pointer to the element previously pushed in or NULL of the queue is emtpy. + */ +void* tlock_pop(tlock_queue_t*); + +/* + * Get number of elements in queue. The value returned is not precise, as this function only locks + * the beginning of the queue, so the return value only garantees the MINIMUM size at the time of + * the function call, but may be bigger if other threads were adding elements concurrently. + * Consequently, this function will block pop calls from other threads, but not push calls. + */ +size_t tlock_min_size(const tlock_queue_t*); + +#endif diff --git a/depcomp b/depcomp new file mode 100644 index 0000000..65cbf70 --- /dev/null +++ b/depcomp @@ -0,0 +1,791 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by 'PROGRAMS ARGS'. + object Object file output by 'PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +# Get the directory component of the given path, and save it in the +# global variables '$dir'. Note that this directory component will +# be either empty or ending with a '/' character. This is deliberate. +set_dir_from () +{ + case $1 in + */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; + *) dir=;; + esac +} + +# Get the suffix-stripped basename of the given path, and save it the +# global variable '$base'. +set_base_from () +{ + base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` +} + +# If no dependency file was actually created by the compiler invocation, +# we still have to create a dummy depfile, to avoid errors with the +# Makefile "include basename.Plo" scheme. +make_dummy_depfile () +{ + echo "#dummy" > "$depfile" +} + +# Factor out some common post-processing of the generated depfile. +# Requires the auxiliary global variable '$tmpdepfile' to be set. +aix_post_process_depfile () +{ + # If the compiler actually managed to produce a dependency file, + # post-process it. + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependency.h'. + # Do two passes, one to just change these to + # $object: dependency.h + # and one to simply output + # dependency.h: + # which is needed to avoid the deleted-header problem. + { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" + sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" + } > "$depfile" + rm -f "$tmpdepfile" + else + make_dummy_depfile + fi +} + +# A tabulation character. +tab=' ' +# A newline character. +nl=' +' +# Character ranges might be problematic outside the C locale. +# These definitions help. +upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ +lower=abcdefghijklmnopqrstuvwxyz +digits=0123456789 +alpha=${upper}${lower} + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Avoid interferences from the environment. +gccflag= dashmflag= + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvisualcpp +fi + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvc7 +fi + +if test "$depmode" = xlc; then + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. + gccflag=-qmakedep=gcc,-MF + depmode=gcc +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. +## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. +## (see the conditional assignment to $gccflag above). +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). Also, it might not be +## supported by the other compilers which use the 'gcc' depmode. +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The second -e expression handles DOS-style file names with drive + # letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the "deleted header file" problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. +## Some versions of gcc put a space before the ':'. On the theory +## that the space means something, we add a space to the output as +## well. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like '#:fec' to the end of the + # dependency line. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ + | tr "$nl" ' ' >> "$depfile" + echo >> "$depfile" + # The second pass generates a dummy entry for each header file. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" + ;; + +xlc) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts '$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + set_dir_from "$object" + set_base_from "$object" + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + aix_post_process_depfile + ;; + +tcc) + # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 + # FIXME: That version still under development at the moment of writing. + # Make that this statement remains true also for stable, released + # versions. + # It will wrap lines (doesn't matter whether long or short) with a + # trailing '\', as in: + # + # foo.o : \ + # foo.c \ + # foo.h \ + # + # It will put a trailing '\' even on the last line, and will use leading + # spaces rather than leading tabs (at least since its commit 0394caf7 + # "Emit spaces for -MD"). + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. + # We have to change lines of the first kind to '$object: \'. + sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" + # And for each line of the second kind, we have to emit a 'dep.h:' + # dummy dependency, to avoid the deleted-header problem. + sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +## The order of this option in the case statement is important, since the +## shell code in configure will try each of these formats in the order +## listed in this file. A plain '-MD' option would be understood by many +## compilers, so we must ensure this comes after the gcc and icc options. +pgcc) + # Portland's C compiler understands '-MD'. + # Will always output deps to 'file.d' where file is the root name of the + # source file under compilation, even if file resides in a subdirectory. + # The object file name does not affect the name of the '.d' file. + # pgcc 10.2 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using '\' : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + set_dir_from "$object" + # Use the source, not the object, to determine the base name, since + # that's sadly what pgcc will do too. + set_base_from "$source" + tmpdepfile=$base.d + + # For projects that build the same source file twice into different object + # files, the pgcc approach of using the *source* file root name can cause + # problems in parallel builds. Use a locking strategy to avoid stomping on + # the same $tmpdepfile. + lockdir=$base.d-lock + trap " + echo '$0: caught signal, cleaning up...' >&2 + rmdir '$lockdir' + exit 1 + " 1 2 13 15 + numtries=100 + i=$numtries + while test $i -gt 0; do + # mkdir is a portable test-and-set. + if mkdir "$lockdir" 2>/dev/null; then + # This process acquired the lock. + "$@" -MD + stat=$? + # Release the lock. + rmdir "$lockdir" + break + else + # If the lock is being held by a different process, wait + # until the winning process is done or we timeout. + while test -d "$lockdir" && test $i -gt 0; do + sleep 1 + i=`expr $i - 1` + done + fi + i=`expr $i - 1` + done + trap - 1 2 13 15 + if test $i -le 0; then + echo "$0: failed to acquire lock after $numtries attempts" >&2 + echo "$0: check lockdir '$lockdir'" >&2 + exit 1 + fi + + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + set_dir_from "$object" + set_base_from "$object" + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" + # Add 'dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in 'foo.d' instead, so we check for that too. + # Subdirectories are respected. + set_dir_from "$object" + set_base_from "$object" + + if test "$libtool" = yes; then + # Libtool generates 2 separate objects for the 2 libraries. These + # two compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir$base.o.d # libtool 1.5 + tmpdepfile2=$dir.libs/$base.o.d # Likewise. + tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + # Same post-processing that is required for AIX mode. + aix_post_process_depfile + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/'"$tab"'\1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/'"$tab"'/ + G + p +}' >> "$depfile" + echo >> "$depfile" # make sure the fragment doesn't end with a backslash + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for ':' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. + "$@" $dashmflag | + sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this sed invocation + # correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process the last invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed '1,2d' "$tmpdepfile" \ + | tr ' ' "$nl" \ + | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E \ + | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + | sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" + echo "$tab" >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/doc/demo.tar.gz b/doc/demo.tar.gz new file mode 100644 index 0000000..3db0165 Binary files /dev/null and b/doc/demo.tar.gz differ diff --git a/include/CAENDig2.h b/include/CAENDig2.h new file mode 100644 index 0000000..d2df66e --- /dev/null +++ b/include/CAENDig2.h @@ -0,0 +1,96 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file CAENDig2.h +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CAENDIG2_H_ +#define CAEN_INCLUDE_CAENDIG2_H_ + +#include + +#define CAEN_DIG2_VERSION_MAJOR 1 +#define CAEN_DIG2_VERSION_MINOR 6 +#define CAEN_DIG2_VERSION_PATCH 1 +#define CAEN_DIG2_VERSION (CAEN_DIG2_VERSION_MAJOR * 10000) + (CAEN_DIG2_VERSION_MINOR * 100) + (CAEN_DIG2_VERSION_PATCH) +#define CAEN_DIG2_VERSION_STRING CAEN_FELIB_STR(CAEN_DIG2_VERSION_MAJOR) "." CAEN_FELIB_STR(CAEN_DIG2_VERSION_MINOR) "." CAEN_FELIB_STR(CAEN_DIG2_VERSION_PATCH) + +#ifdef __cplusplus +extern "C" { +#endif + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_GetLibInfo(char* jsonString, size_t size); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_GetLibVersion(char version[16]); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_GetLastError(char description[1024]); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_DevicesDiscovery(char* jsonString, size_t size, int timeout); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_Open(const char* url, uint32_t* handle); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_Close(uint32_t handle); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_GetDeviceTree(uint32_t handle, char* jsonString, size_t size); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_GetChildHandles(uint32_t handle, const char* path, uint32_t* handles, size_t size); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_GetHandle(uint32_t handle, const char* path, uint32_t* pathHandle); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_GetParentHandle(uint32_t handle, const char* path, uint32_t* parentHandle); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_GetPath(uint32_t handle, char path[256]); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_GetNodeProperties(uint32_t handle, const char* path, char name[32], CAEN_FELib_NodeType_t* type); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_GetValue(uint32_t handle, const char* path, char value[256]); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_SetValue(uint32_t handle, const char* path, const char* value); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_SendCommand(uint32_t handle, const char* path); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_GetUserRegister(uint32_t handle, uint32_t address, uint32_t* value); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_SetUserRegister(uint32_t handle, uint32_t address, uint32_t value); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_SetReadDataFormat(uint32_t handle, const char* jsonString); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_ReadDataV(uint32_t handle, int timeout, va_list args); + +CAEN_FELIB_DLLAPI int CAEN_FELIB_API CAENDig2_HasData(uint32_t handle, int timeout); + +#ifdef __cplusplus +} +#endif + +#endif /* CAEN_INCLUDE_CAENDIG2_H_ */ diff --git a/include/api.hpp b/include/api.hpp new file mode 100644 index 0000000..1a2a91c --- /dev/null +++ b/include/api.hpp @@ -0,0 +1,94 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file api.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_API_HPP_ +#define CAEN_INCLUDE_API_HPP_ + +#include +#include +#include +#include +#include + +#include + +namespace caen { + +namespace dig2 { + +std::string get_lib_info(); + +std::string get_lib_version(); + +std::string device_discovery(int timeout); + +void open(const std::string& url, std::uint32_t& user_handle); + +void close(std::uint32_t handle); + +std::string get_device_tree(std::uint32_t handle); + +std::vector get_child_handles(std::uint32_t handle, const std::string& path); + +std::uint32_t get_handle(std::uint32_t handle, const std::string& path); + +std::uint32_t get_parent_handle(std::uint32_t handle, const std::string& path); + +std::string get_path(std::uint32_t handle); + +std::pair get_node_properties(std::uint32_t handle, const std::string& path); + +std::string get_value(std::uint32_t handle, const std::string& path, const std::string& arg = std::string{}); + +void set_value(std::uint32_t handle, const std::string& path, const std::string& value); + +void send_command(std::uint32_t handle, const std::string& path); + +std::uint32_t get_user_register(std::uint32_t handle, std::uint32_t address); + +void set_user_register(std::uint32_t handle, std::uint32_t address, std::uint32_t value); + +void set_data_format(std::uint32_t handle, const std::string& format); + +void read_data(uint32_t handle, int timeout, va_list* args); + +void has_data(uint32_t handle, int timeout); + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_API_HPP_ */ diff --git a/include/client.hpp b/include/client.hpp new file mode 100644 index 0000000..4b4f170 --- /dev/null +++ b/include/client.hpp @@ -0,0 +1,125 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file client.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CLIENT_HPP_ +#define CAEN_INCLUDE_CLIENT_HPP_ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "cpp-utility/optional.hpp" +#include "endpoints/endpoint.hpp" +#include "library_logger.hpp" +#include "lib_definitions.hpp" + +namespace caen { + +namespace dig2 { + +struct url_data { + + // Standard URI components (RFC 2396) + std::string _scheme; + std::string _authority; + std::string _path; + std::string _query; + std::string _fragment; + + // Custom query fields + caen::optional _monitor; + caen::optional _log_level; + caen::optional _pid; + caen::optional _keepalive; + caen::optional _rcvbuf; + caen::optional _receiver_thread_affinity; + +}; + +url_data parse_url(const std::string& url); + +struct client : private boost::noncopyable { + + client(const url_data& data); + + ~client(); + + std::string get_device_tree(handle::internal_handle_t handle); + std::vector get_child_handles(handle::internal_handle_t handle, const std::string& path); + handle::internal_handle_t get_handle(handle::internal_handle_t handle, const std::string& path); + handle::internal_handle_t get_parent_handle(handle::internal_handle_t handle, const std::string& path); + std::string get_path(handle::internal_handle_t handle); + std::pair get_node_properties(handle::internal_handle_t handle, const std::string& path); + std::string get_value(handle::internal_handle_t handle, const std::string& path, const std::string& arg = std::string{}); + void set_value(handle::internal_handle_t handle, const std::string& path, const std::string& value); + void send_command(handle::internal_handle_t handle, const std::string& path); + std::uint32_t get_user_register(handle::internal_handle_t handle, std::uint32_t address); + void set_user_register(handle::internal_handle_t handle, std::uint32_t address, std::uint32_t value); + void set_data_format(handle::internal_handle_t handle, const std::string& format); + void read_data(handle::internal_handle_t handle, int timeout, std::va_list* args); + void has_data(handle::internal_handle_t handle, int timeout); + bool is_monitor() const noexcept; + + const url_data& get_url_data() const noexcept; + const boost::asio::ip::address& get_address() const noexcept; + const boost::asio::ip::address& get_endpoint_address() const noexcept; + void register_endpoint(std::shared_ptr ep); + const std::list>& get_endpoint_list() const noexcept; + handle::internal_handle_t get_digitizer_internal_handle() const noexcept; + bool is_server_version_aligned() const noexcept; + std::size_t get_n_channels() const noexcept; + double get_sampling_period_ns() const noexcept; + +private: + + struct client_impl; // forward declaration + std::unique_ptr _pimpl; + +}; + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_CLIENT_HPP_ */ diff --git a/include/cpp-utility/COPYING b/include/cpp-utility/COPYING new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/include/cpp-utility/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/include/cpp-utility/COPYING.LESSER b/include/cpp-utility/COPYING.LESSER new file mode 100644 index 0000000..0a04128 --- /dev/null +++ b/include/cpp-utility/COPYING.LESSER @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/include/cpp-utility/args.hpp b/include/cpp-utility/args.hpp new file mode 100644 index 0000000..f63c256 --- /dev/null +++ b/include/cpp-utility/args.hpp @@ -0,0 +1,380 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file args.hpp +* \brief Utilities to copy data structures to `std::va_list` +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_ARGS_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_ARGS_HPP_ + +#include +#include +#include +#include +#include +#include + +#include + +#include "type_traits.hpp" + +namespace caen { + +namespace args { + +namespace detail { + +template +struct container_traits {}; + +template +struct container_traits> { + using value_type = typename Container::value_type; +}; + +template +struct container_traits { + using value_type = T; +}; + +/* + * @brief Wrapper of to get value_type from containers, including C arrays. + * + * Since we are just looking for narrowing conversions, std::remove_cv_t removes qualifiers to simplify checks. + */ +template +using container_value_type_t = std::remove_cv_t::value_type>; + +/* + * @brief Wrapper to get iterator value_type. + * + * Since we are just looking for narrowing conversions, std::remove_cv_t removes qualifiers to simplify checks. + * This also to prevent issues related to LWG issue 2952. + * @sa https://stackoverflow.com/q/71829984/3287591. + */ +template +using iterator_value_type_t = std::remove_cv_t::value_type>; + +/* + * @brief Metafunction to detect if a conversion is narrowing. + * + * List-initialization limits the allowed implicit conversions by prohibiting the narrowing conversions. + * This metafunction should not be used with enumerators because the direct-list-initialization behavior + * from int to enumerator has been changed since C++17. Moreover, the metafunction is broken on some + * compilers: + * - MSCV: narrowing conversion not detected from scoped enums to underlying type integer (fixed on MSVC 19.31) + * - GCC: narrowing conversion not detected from unscoped enums, whose underlying type is not fixed, + * to integers (bug #105255, not fixed as of GCC 11) + * @sa https://en.cppreference.com/w/cpp/language/list_initialization. + * @tparam TOut output type + * @tparam TIn input type + */ +template +struct is_narrowing_conversion : std::true_type {}; + +template +struct is_narrowing_conversion()})>> : std::false_type {}; + +/* + * @brief Same of @ref is_narrowing_conversion, with type conversion. + * + * @tparam It output iterator type + * @tparam Container input container type + */ +template , typename Cv = container_value_type_t> +struct use_explicit_cast : is_narrowing_conversion {}; + +/* + * @brief Metafunction to restrict to arithmetic types (i.e. no enumerators and other stuff). + * + * @tparam It output iterator type + * @tparam Container input container type + */ +template , typename Cv = container_value_type_t> +struct are_arithmetic_types : caen::conjunction< + std::is_arithmetic, + std::is_arithmetic +> {}; + +/* + * @brief Metafuncion returning true if explicit cast is not required and if parameters are arithmetic types. + * + * @tparam It output iterator type + * @tparam Container input container type + */ +template +struct use_copy : caen::conjunction< + caen::negation>, + are_arithmetic_types +> {}; + +/* + * @brief Metafuncion returning true if explicit cast is required and if parameters are arithmetic types. + * + * @tparam It output iterator type + * @tparam Container input container type + */ +template +struct use_transform : caen::conjunction< + use_explicit_cast, + are_arithmetic_types +> {}; + +/* + * @brief Functor that provides explicit static_cast. + * + * @tparam It output iterator type + */ +template +struct cast_into { + + using result_type = iterator_value_type_t; + + template + constexpr result_type operator()(TIn&& value) const noexcept { + static_assert(std::is_nothrow_constructible::value, "it is better to restrict the use to noexcept conversion"); + return static_cast(std::forward(value)); + } + +}; + +namespace sanity_checks { + +enum struct my_scoped_enum : int {}; + +constexpr bool test_container_value_type_t() noexcept { + bool ret{true}; + ret &= (std::is_same, char>::value); + ret &= (std::is_same, char>::value); + ret &= (std::is_same, char>::value); + ret &= (std::is_same, char>::value); + ret &= (!std::is_same, const char>::value); + return ret; +} + +constexpr bool test_iterator_value_type_t() noexcept { + bool ret{true}; + ret &= (std::is_same, char>::value); + ret &= (std::is_same, char>::value); + ret &= (std::is_same, char>::value); + ret &= (std::is_same, char>::value); + ret &= (!std::is_same, const char>::value); + return ret; +} + +constexpr bool test_use_explicit_cast() noexcept { + bool ret{true}; + // cstdint (std::int32_t) + ret &= (!use_explicit_cast::value); + ret &= (!use_explicit_cast::value); + ret &= (!use_explicit_cast::value); + ret &= (!use_explicit_cast::value); + ret &= (use_explicit_cast::value); + ret &= (!use_explicit_cast::value); + ret &= (use_explicit_cast::value); + ret &= (use_explicit_cast::value); + // cstdint (std::uint32_t) + ret &= (!use_explicit_cast::value); + ret &= (use_explicit_cast::value); + ret &= (!use_explicit_cast::value); + ret &= (use_explicit_cast::value); + ret &= (!use_explicit_cast::value); + ret &= (use_explicit_cast::value); + ret &= (use_explicit_cast::value); + ret &= (use_explicit_cast::value); + // const / volatile + ret &= (!use_explicit_cast::value); + ret &= (!use_explicit_cast::value); + ret &= (!use_explicit_cast::value); + ret &= (!use_explicit_cast::value); + // floating point + ret &= (!use_explicit_cast::value); + ret &= (!use_explicit_cast::value); + ret &= (use_explicit_cast::value); + ret &= (use_explicit_cast::value); + ret &= (use_explicit_cast::value); + // no check for enumerators (see comments above) + return ret; +} + +constexpr bool test_are_arithmetic_types() noexcept { + bool ret{true}; + // numeric types + ret &= (are_arithmetic_types::value); + ret &= (are_arithmetic_types::value); + // enumerators (always false) + ret &= (!are_arithmetic_types::value); + ret &= (!are_arithmetic_types::value); + ret &= (!are_arithmetic_types::value); + return ret; +} + +constexpr bool test_use_copy() noexcept { + bool ret{true}; + // numeric types + ret &= (use_copy::value); + ret &= (use_copy::value); + ret &= (use_copy::value); + // enumerators (always false) + ret &= (!use_copy::value); + ret &= (!use_copy::value); + ret &= (!use_copy::value); + return ret; +} + +constexpr bool test_use_transform() noexcept { + bool ret{true}; + // numeric types + ret &= (use_transform::value); + ret &= (use_transform::value); + // enumerators (always false) + ret &= (!use_transform::value); + ret &= (!use_transform::value); + ret &= (!use_transform::value); + return ret; +} + +BOOST_STATIC_ASSERT(test_container_value_type_t()); +BOOST_STATIC_ASSERT(test_iterator_value_type_t()); +BOOST_STATIC_ASSERT(test_use_explicit_cast()); +BOOST_STATIC_ASSERT(test_are_arithmetic_types()); +BOOST_STATIC_ASSERT(test_use_copy()); +BOOST_STATIC_ASSERT(test_use_transform()); + +} // namespace sanity_checks + +/* + * @brief Standard version with explicit cast to silent narrowing conversion warnings. + */ +template +void insert_value(It p, TIn&& value) noexcept { + *p = cast_into{}(std::forward(value)); +} + +/* + * @brief Standard version with `std::copy`, optimized to `std::memmove` when possible. + * + * `std::copy` is perfect: it is implemented in terms of a simple value assignment, and can be optimized + * with `std::memmove` when appropriate. Unfortunately, since the implicit conversion could be a narrowing + * conversions, compilers emits warnings like -Wconversion (gcc/clang) or C4244 (MSVC). + */ +template ::value, int> = 0> +void insert_array(It p, const Container& value) noexcept { + std::copy(std::cbegin(value), std::cend(value), p); +} + +/* + * @brief Fallback version with `std::transform` and explicit cast to avoid warnings about possible loss of data. + * + * Indeed, since the behavior is the same of `std::copy`, we could also use always `std::transform`. + * Unfortunately, no compiler seems to be able to optimize this with `std::memmove` when the type is the same, + * so we explictly use `std::copy` in that case. + */ +template ::value, int> = 0> +void insert_array(It p, const Container& value) noexcept { + std::transform(std::cbegin(value), std::cend(value), p, cast_into{}); +} + +} // namespace detail + +/** + * @brief Copy a variable in a `std::va_list`. + * + * @pre Not restricted to arithmetic types (enum accepted both as input and output). + * @tparam TOut output type + * @tparam TIn input type (must be convertible to @p TOut with no exception) + * @param args a pointer to initialized `std::va_list` + * @param value the value to be copied + */ +template +void insert_value(std::va_list* args, TIn&& value) noexcept { + const auto p = va_arg(*args, TOut*); + detail::insert_value(p, std::forward(value)); +} + +/** + * @brief Copy raw data in a `std::va_list`. + * + * It is always optimized with `std::memmove`. + * @tparam TOut output type + * @tparam TIn input type (must be the same of @p TOut, except for constness) + * @param args a pointer to initialized `std::va_list` + * @param p_in a pointer to source data + * @param size number of elements to copy + */ +template +void insert_raw_data(std::va_list* args, const TIn* p_in, std::size_t size) noexcept { + static_assert(std::is_same>::value, "type must be the same"); + static_assert(std::is_trivially_copyable::value, "is_trivially_copyable is required for std::memmove"); + const auto p = va_arg(*args, TOut*); + std::copy_n(p_in, size, p); +} + +/** + * @brief Copy an array in a `std::va_list`. + * + * It is optimized with `std::memmove` when possible. + * @pre Only arithmetic types are accepted (no enum, struct, ...). + * @tparam TOut output type + * @tparam Container container type (value type must be convertible to @p TOut with no exception) + * @param args a pointer to initialized `std::va_list` + * @param value the container + */ +template +void insert_array(std::va_list* args, const Container& value) noexcept { + const auto p = va_arg(*args, TOut*); + detail::insert_array(p, value); +} + +/** + * @brief Copy a matrix in a `std::va_list`. + * + * It is optimized with `std::memmove` when possible. + * @pre Only arithmetic types are accepted (no enum, struct, ...). + * @tparam TOut output type + * @tparam Container container type, that must be a container of containers (value type must be convertible to @p TOut with no exception) + * @param args a pointer to initialized `std::va_list` + * @param value the container matrix + */ +template +void insert_matrix(std::va_list* args, const Container& value) noexcept { + auto p = va_arg(*args, TOut**); + for (auto&& v : value) + detail::insert_array(*p++, std::forward(v)); +} + +} // namespace args + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_ARGS_HPP_ */ diff --git a/include/cpp-utility/bit.hpp b/include/cpp-utility/bit.hpp new file mode 100644 index 0000000..530ce65 --- /dev/null +++ b/include/cpp-utility/bit.hpp @@ -0,0 +1,735 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file bit.hpp +* \brief Bit manipulation utilities +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_BIT_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_BIT_HPP_ + +#include +#include +#include +#include +#include +#include + +#if defined(__has_include) && __has_include() +#include // C++20 +#endif + +#ifdef __cpp_lib_bit_cast +#include +#endif + +#include +#include +#include +#include + +#include "integer.hpp" + +namespace caen { + +namespace bit { + +namespace detail { + +template +struct bit_size : std::integral_constant {}; + +template +constexpr TOut get_bit_unsafe(std::size_t pos) noexcept { + return TOut{1} << pos; +} + +template +constexpr TOut get_bit(std::size_t pos) { + if (pos >= bit_size::value) + throw std::range_error("get_bit type is too small"); + return get_bit_unsafe(pos); +} + +template +constexpr TOut get_mask_unsafe(std::size_t nbits) noexcept { + return (nbits < bit_size::value) ? (get_bit_unsafe(nbits) - TOut{1}) : std::numeric_limits::max(); +} + +template +constexpr TOut get_mask(std::size_t nbits) { + if (nbits > bit_size::value) + throw std::range_error("get_mask type is too small"); + return get_mask_unsafe(nbits); +} + +#if BOOST_PREDEF_WORKAROUND(BOOST_COMP_GNUC, <, 6, 1, 0) + +// avoid never executed "throw" in constexpr function (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67371) + +template ::value), int> = 0> +constexpr TOut get_bit() noexcept { + return get_bit_unsafe(Pos); +} + +template ::value), int> = 0> +constexpr TOut get_mask() noexcept { + return get_mask_unsafe(NBits); +} + +#else + +template +constexpr TOut get_bit() noexcept { + return get_bit(Pos); +} + +template +constexpr TOut get_mask() noexcept { + return get_mask(NBits); +} + +#endif + +#ifndef __cpp_lib_bit_cast +inline +#endif +namespace no_std_bit_cast { + +// cannot be done `constexpr` because it requires compiler support. (https://en.cppreference.com/w/cpp/numeric/bit_cast) +template +TOut bit_cast(const TIn& src) noexcept { + TOut dst; + std::memcpy(&dst, &src, sizeof(dst)); + return dst; +} + +// corner case when all scalar types have sizeof equal to 1 is not supported. (https://en.cppreference.com/w/cpp/types/endian) +enum class endian { + little = 1234, + big = 4321, + +#if BOOST_ENDIAN_BIG_BYTE +#ifdef CAEN_BIT_ENDIAN_DETECTED +#error endian already defined +#endif +#define CAEN_BIT_ENDIAN_DETECTED + native = little, +#endif + +#if BOOST_ENDIAN_BIG_WORD +#ifdef CAEN_BIT_ENDIAN_DETECTED +#error endian already defined +#endif +#define CAEN_BIT_ENDIAN_DETECTED + native = 2143, +#endif + +#if BOOST_ENDIAN_LITTLE_BYTE +#ifdef CAEN_BIT_ENDIAN_DETECTED +#error endian already defined +#endif +#define CAEN_BIT_ENDIAN_DETECTED + native = little, +#endif + +#if BOOST_ENDIAN_LITTLE_WORD +#ifdef CAEN_BIT_ENDIAN_DETECTED +#error endian already defined +#endif +#define CAEN_BIT_ENDIAN_DETECTED + native = 3412, +#endif + +#ifndef CAEN_BIT_ENDIAN_DETECTED + native = 0, +#endif +#undef CAEN_BIT_ENDIAN_DETECTED +}; + +template +constexpr UnsignedInt sign_extend(UnsignedInt v) noexcept { + static_assert(-1 == ~0, "sign_extend requires two's complement architecture"); + constexpr auto mask = get_bit(); + return (v ^ mask) - mask; +} + +// cannot be done `constexpr` because it requires bit_cast. +template +SignedInt sign_extend_cast(UnsignedInt v) noexcept { + return bit_cast(sign_extend(v)); +} + +} // namespace no_std_bit_cast + +#ifdef __cpp_lib_bit_cast +inline namespace std_bit_cast { + +using std::bit_cast; +using std::endian; + +template +constexpr UnsignedInt sign_extend(UnsignedInt v) noexcept { + // two's complement is mandatory since C++20 + constexpr auto mask = get_bit(); + return (v ^ mask) - mask; +} + +// static_cast is sufficient since C++20 and can be `constexpr` (https://stackoverflow.com/a/57947296/3287591) +template +constexpr SignedInt sign_extend_cast(UnsignedInt v) noexcept { + return static_cast(sign_extend(v)); +} + +} // namespace std_bit_cast +#endif + +#ifndef __cpp_lib_bit_cast +#define CAEN_BIT_CXX20_COSTEXPR +#else +#define CAEN_BIT_CXX20_COSTEXPR constexpr +#endif + +template +struct is_unsigned : std::is_unsigned {}; + +template +struct is_unsigned::value>> : is_unsigned> {}; + +namespace sanity_checks { + +#if BOOST_COMP_MSVC || defined(BOOST_COMP_MSVC_EMULATED) +/* + * In versions of Visual Studio before Visual Studio 2022 version 17.4, the C++ compiler didn't + * correctly determine the underlying type of an unscoped enumeration with no fixed base type. + * The compiler also didn't correctly model the types of enumerators. It could assume an incorrect + * type in enumerations without a fixed underlying type before the closing brace of the enumeration. + * Under /Zc:enumTypes, the compiler correctly implements the standard behavior. + * + * Unfortunately, /Zc:enumTypes is not enabled by default because it is a potential source and + * binary breaking change. + * + * If /Zc:enumTypes would be enabled, we could also replace BOOST_COMP_MSVC with the classic + * BOOST_PREDEF_WORKAROUND(BOOST_COMP_MSVC, <, 19, 34, 0). BOOST_COMP_MSVC_EMULATED is a workaround + * for IntelliSense, that is still broken. + * + * See: + * - https://learn.microsoft.com/en-us/cpp/overview/cpp-conformance-improvements?view=msvc-170 + * - https://developercommunity.visualstudio.com/t/underlying-type-of-an-unscoped-enum/524018 + */ +#define CAEN_SKIP_ENUM_AUTO_UNSIGNED_TEST +#endif + +using signed_t = signed char; +using unsigned_t = unsigned char; + +// enum my_enum_opaque; bad defined +enum my_enum_opaque_signed : signed_t; +enum my_enum_opaque_unsigned : unsigned_t; +enum my_enum {}; +enum my_enum_auto_signed { _vsm = -1 }; +#ifndef CAEN_SKIP_ENUM_AUTO_UNSIGNED_TEST +enum my_enum_auto_unsigned { _vum = std::numeric_limits::max() }; +#endif +enum my_enum_signed : signed_t {}; +enum my_enum_unsigned : unsigned_t {}; +enum struct my_enum_opaque_scoped; +enum struct my_enum_opaque_scoped_signed : signed_t; +enum struct my_enum_opaque_scoped_unsigned : unsigned_t; +enum struct my_enum_scoped {}; +enum struct my_enum_scoped_signed : signed_t {}; +enum struct my_enum_scoped_unsigned : unsigned_t {}; + +constexpr bool test_is_unsigned() noexcept { + bool ret{true}; + ret &= (is_unsigned::value); + ret &= (is_unsigned::value == (CHAR_MIN != SCHAR_MIN)); // implementation defined: signed on gcc and clang (settable with -funsigned-char), signed on MSVC (settable with /J) + ret &= (is_unsigned::value); + ret &= (!is_unsigned::value); + ret &= (is_unsigned::value); + ret &= (!is_unsigned::value); + ret &= (!is_unsigned::value); + ret &= (!is_unsigned::value); + ret &= (!is_unsigned::value); + ret &= (is_unsigned::value); + ret &= (is_unsigned::value || true); // implementation defined: unsigned on gcc and clang, signed on MSVC + ret &= (!is_unsigned::value); +#ifndef CAEN_SKIP_ENUM_AUTO_UNSIGNED_TEST + ret &= (is_unsigned::value); // implementation broken on MSCV +#endif + ret &= (!is_unsigned::value); + ret &= (is_unsigned::value); + ret &= (!is_unsigned::value); + ret &= (!is_unsigned::value); + ret &= (is_unsigned::value); + ret &= (!is_unsigned::value); + ret &= (!is_unsigned::value); + ret &= (is_unsigned< my_enum_scoped_unsigned>::value); + return ret; +} + +BOOST_STATIC_ASSERT(test_is_unsigned()); + +} // namespace sanity_checks + +template +constexpr TOut mask_at(TIn v) noexcept { + return static_cast((v >> Lsb) & get_mask()); +} + +template ::value), int> = 0> +constexpr void right_shift(TIn& v) noexcept { + v >>= NBits; +} + +template ::value), int> = 0> +constexpr void right_shift(TIn& v) noexcept { + v = TIn{}; // set to zero +} + +template +constexpr TOut mask_and_right_shift(TIn& v) noexcept { + const TOut res = mask_at(v); + right_shift(v); + return res; +} + +template ::value), int> = 0> +constexpr void left_shift(TIn& v) noexcept { + v <<= NBits; +} + +template ::value), int> = 0> +constexpr void left_shift(TIn& v) noexcept { + v = TIn{}; // set to zero +} + +template +constexpr TOut mask_and_left_shift(TIn &v) noexcept { + constexpr std::size_t offset = bit_size::value - NBits; + const TOut res = mask_at(v); + left_shift(v); + return res; +} + +template +constexpr bool test(TIn v) noexcept { + return (get_bit() & v) != 0; +} + +template +constexpr void set(TIn& v) noexcept { + v |= get_bit(); +} + +} // namespace detail + +/** + * @brief Get number of bits of a type at compile time. + */ +using detail::bit_size; + +/** + * @brief Get an integer with given bit set. + */ +using detail::get_bit; + +/** + * @brief Get an integer with all first given number of bit set. + */ +using detail::get_mask; + +/** + * @brief Replacement for `std::endian` on pre C++20. + */ +using detail::endian; + +/** + * @brief Replacement for `std::bit_cast` on pre C++20. + * + * Useful because `reinterpret_cast` generate a undefined behavior for strict aliasing rule. + * @note `constexpr` requires C++20. + * @sa https://en.cppreference.com/w/cpp/numeric/bit_cast + * @tparam TOut output type + * @tparam TIn input type + * @param v input value + * @return result + */ +template +CAEN_BIT_CXX20_COSTEXPR TOut bit_cast(const TIn& v) noexcept { + static_assert(sizeof(TIn) == sizeof(TOut), "input type and output type must have the same size"); + static_assert(std::is_trivially_copyable::value, "invalid input type"); + static_assert(std::is_trivially_copyable::value, "invalid output type"); + static_assert(std::is_trivially_constructible::value, "invalid output type"); + return detail::bit_cast(v); +} + +/** + * @brief Extend the sign bit in a unsigned type value, returning the same unsigned type. + * + * @warning Does not work if any bit above NBits is set on @arg v. + * @tparam NBits number of significant bits in input value @arg v + * @tparam UnsignedInt input type (unsigned, must contain at least NBits bits) + * @param[in] v input value + * @return result + */ +template +constexpr UnsignedInt sign_extend(UnsignedInt v) noexcept { + static_assert(std::is_unsigned::value, "input type must be unsigned (enumerators not supported)"); + static_assert(NBits != 0, "NBits cannot be zero"); + static_assert(NBits != 0 && NBits <= bit_size::value, "type is too small"); + return detail::sign_extend(v); +} + +/** + * @brief Sign extend with automatic bit cast to corresponding signed type. + * + * @note `constexpr` requires C++20. + * @tparam NBits width of input value + * @tparam UnsignedInt input type + * @tparam SignedInt output type + * @param v input value + * @return the result + */ +template > +CAEN_BIT_CXX20_COSTEXPR SignedInt sign_extend_cast(UnsignedInt v) noexcept { + static_assert(std::is_unsigned::value, "input type must be unsigned (enumerators not supported)"); + static_assert(std::is_signed::value, "output type must be signed (enumerators not supported)"); + return detail::sign_extend_cast(v); +} + +/** + * @brief Right shift the argument by NBits. + * + * @tparam NBits number of bits + * @tparam TIn input type (unsigned, must contain at least NBits bits) + * @param v the input value that will be shifted + */ +template +constexpr void right_shift(TIn& v) noexcept { + static_assert(detail::is_unsigned::value, "input type must be unsigned"); + static_assert(NBits <= bit_size::value, "input type is too small"); + detail::right_shift(v); +} + +/** + * @brief Left shift the argument by NBits. + * + * @tparam NBits number of bits + * @tparam TIn input type (unsigned, must contain at least NBits bits) + * @param v the input value that will be shifted + */ +template +constexpr void left_shift(TIn& v) noexcept { + static_assert(detail::is_unsigned::value, "input type must be unsigned"); + static_assert(NBits <= bit_size::value, "input type is too small"); + detail::left_shift(v); +} + +/** + * @brief Get the lowest NBits from argument, and right shift the argument. + * + * @tparam NBits number of bits + * @tparam TOut output type (unsigned, must contain at least NBits bits) + * @tparam TIn input type (unsigned, must contain at least NBits bits) + * @param v the input value that will be shifted + * @return the value stored in the lowest NBits of v + */ +template ::fast, typename TIn> +constexpr TOut mask_and_right_shift(TIn& v) noexcept { + static_assert(detail::is_unsigned::value, "input type must be unsigned"); + static_assert(detail::is_unsigned::value, "result type must be unsigned"); + static_assert(NBits <= bit_size::value, "input type is too small"); + static_assert(NBits <= bit_size::value, "result type is too small"); + static_assert(!std::is_same::value || (NBits == 1), "bool requires NBits == 1"); + static_assert(!std::is_same::value || (NBits == 1), "bool requires NBits == 1"); + return detail::mask_and_right_shift(v); +} + +/** + * @brief Convenience function for template argument deduction. + * + * @overload + */ +template +constexpr void mask_and_right_shift(TIn& v, TOut& res) noexcept { + res = mask_and_right_shift(v); +} + +/** + * @brief Get the highest NBits from argument, and left shift the argument. + * + * @warning Slower than mask_and_right_shift, requiring 2 shifts instead of 1. + * @tparam NBits number of bits + * @tparam TOut output type (unsigned, must contain at least NBits bits) + * @tparam TIn input type (unsigned, must contain at least NBits) + * @param v the input value that will be shifted + * @return the value stored in the highest NBits of v + */ +template ::fast, typename TIn> +constexpr TOut mask_and_left_shift(TIn& v) noexcept { + static_assert(detail::is_unsigned::value, "input type must be unsigned"); + static_assert(detail::is_unsigned::value, "result type must be unsigned"); + static_assert(NBits <= bit_size::value, "input type is too small"); + static_assert(NBits <= bit_size::value, "result type is too small"); + static_assert(!std::is_same::value || (NBits == 1), "bool requires NBits == 1"); + static_assert(!std::is_same::value || (NBits == 1), "bool requires NBits == 1"); + return detail::mask_and_left_shift(v); +} + +/** + * @brief Convenience function for template argument deduction. + * + * @overload + */ +template +constexpr void mask_and_left_shift(TIn& v, TOut& res) noexcept { + res = mask_and_left_shift(v); +} + +/** + * @brief Get a value masking argument at given position. + * + * @tparam NBits number of bits + * @tparam Lsb start position + * @tparam TOut output type (unsigned, must contain at least NBits bits) + * @tparam TIn input type (unsigned, must contain at least NBits + Lsb bits) + * @param v the input value + * @return the value stored in the NBits of v starting at Lsb + */ +template ::fast, typename TIn> +constexpr TOut mask_at(TIn v) noexcept { + static_assert(detail::is_unsigned::value, "input type must be unsigned"); + static_assert(detail::is_unsigned::value, "result type must be unsigned"); + static_assert(NBits + Lsb <= bit_size::value, "input type is too small"); + static_assert(NBits <= bit_size::value, "result type is too small"); + static_assert(!std::is_same::value || (NBits == 1), "bool requires NBits == 1"); + static_assert(!std::is_same::value || ((NBits == 1) && (Lsb == 0)), "bool requires NBits == 1 and Lsb == 0"); + return detail::mask_at(v); +} + +/** + * @brief Convenience function for template argument deduction. + * + * @overload + */ +template +constexpr void mask_at(const TIn v, TOut& res) noexcept { + res = mask_at(v); +} + +/** + * @brief Test if a bit is set. + * + * @tparam Pos bit index + * @tparam TIn input type (unsigned, must contain at least Pos + 1 bits) + * @param v the input value + * @return true if selected bit is set + */ +template +constexpr bool test(TIn v) noexcept { + static_assert(detail::is_unsigned::value, "input type must be unsigned"); + static_assert(Pos < bit_size::value, "input type is too small"); + static_assert(!std::is_same::value || (Pos == 0), "bool requires Pos == 0"); + return detail::test(v); +} + +/** + * @brief Set a bit. + * + * @tparam Pos bit index + * @tparam TIn input type (unsigned, must contain at least Pos + 1 bits) + * @param v the input value + */ +template +constexpr void set(TIn& v) noexcept { + static_assert(detail::is_unsigned::value, "input type must be unsigned"); + static_assert(Pos < bit_size::value, "input type is too small"); + static_assert(!std::is_same::value || (Pos == 0), "bool requires Pos == 0"); + detail::set(v); +} + +// sanity checks +namespace sanity_checks { + +constexpr bool test_bit_size() noexcept { + bool ret{true}; + ret &= (bit_size::value == CHAR_BIT); + ret &= (bit_size::value == 8); + ret &= (bit_size::value == 16); + ret &= (bit_size::value == 32); + ret &= (bit_size::value == 64); + ret &= (bit_size::value == 8); + ret &= (bit_size::value == 16); + ret &= (bit_size::value == 32); + ret &= (bit_size::value == 64); + ret &= (bit_size::value >= 8); + ret &= (bit_size::value >= 16); + ret &= (bit_size::value >= 32); + ret &= (bit_size::value >= 64); + return ret; +} + +constexpr bool test_sign_extend() noexcept { + bool ret{true}; + ret &= (sign_extend<4, std::uint8_t>(0b0000'1111) == 0b1111'1111); + ret &= (sign_extend<5, std::uint8_t>(0b0000'1111) == 0b0000'1111); + ret &= (sign_extend<4, std::uint8_t>(0b0000'0111) == 0b0000'0111); + ret &= (sign_extend<5, std::uint16_t>(0b0000'0000'0001'0001) == 0b1111'1111'1111'0001); + ret &= (sign_extend<6, std::uint16_t>(0b0000'0000'0001'0001) == 0b0000'0000'0001'0001); + return ret; +} + +constexpr bool test_sign_extend_bad() noexcept { + bool ret{true}; + // not working if input value bits above NBits are not zero + ret &= (sign_extend<4, std::uint8_t>(0b1100'1111) != 0b1111'1111); + ret &= (sign_extend<5, std::uint8_t>(0b1100'1111) != 0b0000'1111); + return ret; +} + +constexpr bool test_sign_extend_cast() noexcept { + bool ret{true}; +#ifdef __cpp_lib_bit_cast + ret &= (sign_extend_cast<4, std::uint8_t>(0b0000'1111) == std::int8_t{-1}); + ret &= (sign_extend_cast<5, std::uint8_t>(0b0000'1111) == std::int8_t{15}); + ret &= (sign_extend_cast<4, std::uint8_t>(0b0000'0111) == std::int8_t{7}); + ret &= (sign_extend_cast<5, std::uint16_t>(0b0000'0000'0001'0001) == std::int16_t{-15}); + ret &= (sign_extend_cast<6, std::uint16_t>(0b0000'0000'0001'0001) == std::int16_t{17}); +#endif + return ret; +} + +constexpr bool test_mask_at() noexcept { + const std::uint32_t b{0x01234567}; + bool ret{true}; + ret &= (mask_at<4, 0>(b) == uint_t<4>::fast{0x7}); + ret &= (mask_at<4, 8>(b) == uint_t<4>::fast{0x5}); + ret &= (mask_at<12, 20>(b) == uint_t<12>::fast{0x012}); + ret &= (mask_at<32, 0>(b) == uint_t<32>::fast{0x01234567}); + ret &= (mask_at<0, 27>(b) == uint_t<0>::fast{0x0}); + return ret; +} + +constexpr bool test_right_shift() noexcept { + std::uint32_t b{0x01234567}; + bool ret{true}; + right_shift<24>(b); + ret &= (b == std::uint32_t{0x01}); + return ret; +} + +constexpr bool test_left_shift() noexcept { + std::uint32_t b{0x01234567}; + bool ret{true}; + left_shift<24>(b); + ret &= (b == std::uint32_t{0x67000000}); + return ret; +} + +constexpr bool test_mask_and_right_shift() noexcept { + std::uint32_t b{0x01234567}; + bool ret{true}; + ret &= (mask_and_right_shift<16>(b) == uint_t<16>::fast{0x4567}); + ret &= (mask_and_right_shift<16>(b) == uint_t<16>::fast{0x0123}); + ret &= (b == 0); + return ret; +} + +constexpr bool test_mask_and_left_shift() noexcept { + std::uint32_t b{0x01234567}; + bool ret{true}; + ret &= (mask_and_left_shift<16>(b) == uint_t<16>::fast{0x0123}); + ret &= (mask_and_left_shift<16>(b) == uint_t<16>::fast{0x4567}); + ret &= (b == 0); + return ret; +} + +constexpr bool test_mask_and_shift_max() noexcept { + std::uint64_t b1{0x0123456789abcdef}; + auto b2{b1}; + const auto b_copy{b1}; + bool ret{true}; + ret &= (mask_and_right_shift<64, std::uint64_t>(b1) == b_copy); + ret &= (mask_and_left_shift<64, std::uint64_t>(b2) == b_copy); + ret &= (b1 == 0); + ret &= (b2 == 0); + return ret; +} + +constexpr bool test_test() noexcept { + std::uint16_t b{0b101}; + bool ret{true}; + ret &= (test<0>(b)); + ret &= (!test<1>(b)); + ret &= (test<2>(b)); + ret &= (!test<3>(b)); + ret &= (!test<4>(b)); + return ret; +} + +constexpr bool test_set() noexcept { + std::uint16_t b{}; + set<0>(b); + set<2>(b); + set<3>(b); + bool ret{true}; + ret &= (b == std::uint16_t{0b1101}); + return ret; +} + +BOOST_STATIC_ASSERT(test_bit_size()); +BOOST_STATIC_ASSERT(test_sign_extend()); +BOOST_STATIC_ASSERT(test_sign_extend_bad()); +BOOST_STATIC_ASSERT(test_sign_extend_cast()); +BOOST_STATIC_ASSERT(test_mask_at()); +BOOST_STATIC_ASSERT(test_right_shift()); +BOOST_STATIC_ASSERT(test_left_shift()); +BOOST_STATIC_ASSERT(test_mask_and_right_shift()); +BOOST_STATIC_ASSERT(test_mask_and_left_shift()); +BOOST_STATIC_ASSERT(test_mask_and_shift_max()); +BOOST_STATIC_ASSERT(test_test()); +BOOST_STATIC_ASSERT(test_set()); + +} // namespace sanity_checks + +} // namespace bit + +// import also into caen namespace (for consistency with std) +using bit::bit_cast; +using bit::endian; + +} // namespace caen + +#undef CAEN_SKIP_ENUM_AUTO_UNSIGNED_TEST + +#endif /* CAEN_INCLUDE_CPP_UTILITY_BIT_HPP_ */ diff --git a/include/cpp-utility/byte.hpp b/include/cpp-utility/byte.hpp new file mode 100644 index 0000000..0740fae --- /dev/null +++ b/include/cpp-utility/byte.hpp @@ -0,0 +1,153 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file byte.hpp +* \brief `std::byte` replacement +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_BYTE_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_BYTE_HPP_ + +#include + +#if __cplusplus >= 201703L +#include +#endif + +#include +#include +#include + +namespace caen { + +#if __cplusplus < 201703L +inline +#endif +namespace pre_cxx17 { + +/** + * @brief Replacement for `std::byte`. + * + * Scoped enum is the best choice to emulate `std::byte`. The main difference is that on + * C++14 it is not possible to use direct-list-initialization on enumeration types. So, + * something like `caen::byte{1};`, legal in C++17, is not legal on C++14. This is a + * language feature, cannot be implemented in terms of code, unless byte is implemented + * as a typedef, like `using byte = unsigned char;`. + * @warning On C++14 this breaks the strict aliasing rule, even if it seems to work properly. + * @sa https://stackoverflow.com/a/44126731/3287591 + * @sa https://en.cppreference.com/w/cpp/types/byte + */ +#if BOOST_PREDEF_WORKAROUND(BOOST_COMP_GNUC, <, 6, 0, 0) +// workaround for GCC bug #43407 +enum class byte : unsigned char BOOST_MAY_ALIAS {}; +#else +enum class BOOST_MAY_ALIAS byte : unsigned char {}; +#endif + +template ::value, int> = 0> +constexpr byte operator<<(byte b, IntegerType shift) noexcept { + return byte(static_cast(b) << shift); +} +template ::value, int> = 0> +constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept { + return b = b << shift; +} +template ::value, int> = 0> +constexpr byte operator>>(byte b, IntegerType shift) noexcept { + return byte(static_cast(b) >> shift); +} +template ::value, int> = 0> +constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept { + return b = b >> shift; +} +constexpr byte operator|(byte l, byte r) noexcept { + return byte(static_cast(l) | static_cast(r)); +} +constexpr byte& operator|=(byte& l, byte r) noexcept { + return l = l | r; +} +constexpr byte operator&(byte l, byte r) noexcept { + return byte(static_cast(l) & static_cast(r)); +} +constexpr byte& operator&=(byte& l, byte r) noexcept { + return l = l & r; +} +constexpr byte operator^(byte l, byte r) noexcept { + return byte(static_cast(l) ^ static_cast(r)); +} +constexpr byte& operator^=(byte& l, byte r) noexcept { + return l = l ^ r; +} +constexpr byte operator~(byte b) noexcept { + return byte(~static_cast(b)); +} +template ::value, int> = 0> +constexpr IntegerType to_integer(byte b) noexcept { + return IntegerType(b); +} + +} // namespace pre_cxx17 + +#if __cplusplus >= 201703L +inline namespace cxx17 { + +/** + * @brief Fallback to standard version std::byte, if available. + */ +using std::byte; +using std::to_integer; + +} // namespace cxx17 +#endif + +namespace sanity_checks { + +static_assert(sizeof(byte) == sizeof(unsigned char), "byte size must be 1"); + +// requirements for fast vector allocation with std::memset +static_assert(std::is_standard_layout::value, "is_standard_layout required for safe pointer conversion with reinterpret_cast"); + +// requirements for fast vector copy with std::memcpy (C++14@[basic.types], https://stackoverflow.com/a/7624942/3287591) +static_assert(std::is_trivially_copyable::value, "is_trivially_copyable required for fast vector copy"); + +// requirements for fast vector allocation on MSVC debug +static_assert(std::is_scalar::value, "is_scalar required for fast assignment in MSVC debug"); +static_assert(!std::is_volatile::value, "!is_volatile required for fast assignment in MSVC debug"); +static_assert(!std::is_member_pointer::value, "!is_member_pointer required for fast assignment in MSVC debug"); + +static_assert(to_integer(byte{}) == int{}, "invalid to_integer implementation"); + +} // namespace sanity_checks + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_BYTE_HPP_ */ diff --git a/include/cpp-utility/circular_buffer.hpp b/include/cpp-utility/circular_buffer.hpp new file mode 100644 index 0000000..89f3fd8 --- /dev/null +++ b/include/cpp-utility/circular_buffer.hpp @@ -0,0 +1,348 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file circular_buffer.hpp +* \brief Circular buffer +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_CIRCULAR_BUFFER_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_CIRCULAR_BUFFER_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "scoped_set.hpp" +#include "to_address.hpp" + +namespace caen { + +template // last parameter to be removed, legacy support for timeout type +class circular_buffer { +public: + + /* + * Notes on the implementation. + * + * 1. Why the internal buffer is implemented using a std::array instead of a + * std::vector? + * + * Even if not strictly necessary, if the constant N is known at compile time, + * there can be some interesting optimizations. For example, size() relies on + * modulo operation. If the divisor is not known at compile time, an integer + * division is required, but, if N is a compile time constant, the modulo + * operation is optimized using either the Montgomery modular multiplication + * or, if N is a power of 2, a single AND operation with a mask. + * + * 2. Why capacity is N - 1? + * + * Since the circular buffer is implemented using two iterators that always + * point to valid iterators of the internal container (i.e. never pointing to + * the container end), there is no way to distinguish the empty case and the + * full case when the two iterators are equal. This allow the get_buffer_write + * to be non blocking, because there is always at least an element that can + * be written. + */ + + static_assert(N > 0, "N cannot be zero"); + + using container_type = std::array; + using value_type = typename container_type::value_type; + using size_type = typename container_type::size_type; + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; + using reference = typename container_type::reference; + using const_reference = typename container_type::const_reference; + using pointer = typename container_type::pointer; + using const_pointer = typename container_type::const_pointer; + + template + static constexpr Timeout infinite_timeout() { + return Timeout{-1}; + } + +#if BOOST_PREDEF_WORKAROUND(BOOST_COMP_GNUC, <, 12, 0, 0) + /* + * Due to GCC bug 71165, fixed on GCC 12, the aggregate initialization + * of buffer, for large value of N, would generate large code and + * take a lot of time to compile. As a workaround we use fill(). + */ + circular_buffer() + : _read_iterator{_buffer.begin()} + , _write_iterator{_buffer.begin()} + , _valid{true} + , _halt{false} + , _read_halt{true} + , _write_halt{true} + , _read_pending{false} { + _buffer.fill(T{}); + } +#else + circular_buffer() + : _buffer{} + , _read_iterator{_buffer.begin()} + , _write_iterator{_buffer.begin()} + , _valid{true} + , _halt{false} + , _read_halt{true} + , _write_halt{true} + , _read_pending{false} { + } +#endif + + ~circular_buffer() = default; + + constexpr std::size_t capacity() const noexcept { + return _buffer.size() - 1; + } + + void apply_all(std::function f) { + supervisor_call([this, &f] { + _valid = false; + _read_iterator = _buffer.begin(); + _write_iterator = _buffer.begin(); + std::for_each(_buffer.begin(), _buffer.end(), f); + }); + } + + void invalidate_buffers() { + supervisor_call([this] { + _valid = false; + _read_iterator = _buffer.begin(); + _write_iterator = _buffer.begin(); + }); + } + + // atomic function to clear and insert a fake event manipulated with f + void fake_write(std::function f) { + supervisor_call([this, &f] { + _valid = true; + _read_iterator = _buffer.begin(); + _write_iterator = _buffer.begin() + 1; + f(_buffer.front()); + }); + } + + bool has_data() { + std::unique_lock lk(_mtx); + return valid_and_not_empty(); + } + + void wait_empty() { + std::unique_lock lk(_mtx); + _cv.wait(lk, [this] { return valid_and_empty(); }); + } + + void notify() noexcept { + _cv.notify_all(); + } + + const_pointer get_buffer_read() { + return get_buffer_read(infinite_timeout()); + } + + template + const_pointer get_buffer_read(Timeout timeout) { + std::unique_lock lk(_mtx); + // prevent this function to be called by two threads until the buffer is released + if (BOOST_UNLIKELY(_read_pending)) + throw std::runtime_error("another call to get_buffer_read is pending"); + scoped_set ss(_read_pending, true); + auto condition = [this] { return valid_and_not_empty(); }; + switch (timeout.count()) { + case infinite_timeout().count(): + _cv.wait(lk, condition); + break; + case decltype(timeout)::zero().count(): + // special case to avoid wait with 0 timeout + if (!condition()) + return nullptr; + break; + default: + if (!_cv.wait_for(lk, timeout, condition)) + return nullptr; + break; + } + ss.release(); + _read_halt = false; + // no need to notify for _read_halt set to false + return caen::to_address(_read_iterator); + } + + void abort_reading() { + finalize_reading(); + } + + void end_reading() { + finalize_reading(); + notify(); + } + + void end_reading_relaxed() { + const auto current_size = finalize_reading(); + if (current_size == 0) + notify(); + } + + pointer get_buffer_write() { + std::unique_lock lk(_mtx); + _write_halt = false; + _valid = true; // can be set to false by supervisor calls + // no need to notify for _write_halt set to false + return caen::to_address(_write_iterator); + } + + void abort_writing() { + finalize_writing(); + } + + void end_writing() { + finalize_writing(); + notify(); + } + + void end_writing_relaxed() { + const auto current_size = finalize_writing(); + if (current_size == capacity()) + notify(); + } + + bool is_read_pending() { + std::unique_lock lk(_mtx); + return _read_pending; + } + + [[deprecated("renamed is_read_pending")]] bool is_get_buffer_read_pending() { + return is_read_pending(); + } + +private: + + bool empty() const noexcept { + return _write_iterator == _read_iterator; + } + + std::size_t size() const noexcept { + return (_write_iterator - _read_iterator) % _buffer.size(); + } + + void handle_supervisor_halt(std::unique_lock& lk) { + if (_halt) { + lk.unlock(); + _cv_supervisor.notify_all(); + lk.lock(); + } + } + + template + std::size_t finalize_reading() { + std::unique_lock lk(_mtx); + if (Success) + increment_iterator(_read_iterator); + _read_halt = true; + handle_supervisor_halt(lk); + _read_pending = false; + return size(); + } + + template + std::size_t finalize_writing() { + std::unique_lock lk(_mtx); + _write_halt = true; + handle_supervisor_halt(lk); + if (Success) { + _cv.wait(lk, [this] { return !_halt && !full(); }); + if (_valid) // could be set to false by supervisor calls + increment_iterator(_write_iterator); + } else { + _cv.wait(lk, [this] { return !_halt; }); + } + return size(); + } + + bool valid() const noexcept { + return !_halt && _valid; + } + + bool valid_and_not_empty() const noexcept { + return valid() && !empty(); + } + + bool valid_and_empty() const noexcept { + return valid() && empty(); + } + + bool full() const noexcept { + return size() == capacity(); + } + + template + void increment_iterator(It& it) noexcept { + if (++it == _buffer.end()) + it = _buffer.begin(); + } + + template + void supervisor_call(const Callable &call) { + { + std::unique_lock lk(_mtx); + scoped_set ss(_halt, true); + _cv_supervisor.wait(lk, [this] { return _read_halt && _write_halt; }); + call(); + } + notify(); + } + + container_type _buffer; + const_iterator _read_iterator; + iterator _write_iterator; + bool _valid; + bool _halt; + bool _read_halt; + bool _write_halt; + bool _read_pending; + mutable std::mutex _mtx; + mutable std::condition_variable _cv; + mutable std::condition_variable _cv_supervisor; +}; + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_CIRCULAR_BUFFER_HPP_ */ diff --git a/include/cpp-utility/counting_range.hpp b/include/cpp-utility/counting_range.hpp new file mode 100644 index 0000000..9e4ac13 --- /dev/null +++ b/include/cpp-utility/counting_range.hpp @@ -0,0 +1,58 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file counting_range.hpp +* \brief Counting range +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_COUNTING_RANGE_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_COUNTING_RANGE_HPP_ + +#include + +namespace caen { + +/** + * @brief Wrapper of boost::counting_range that simplify generation of [0, last) ranges deducing the type of 0. + * + * @tparam ValueT value type + * @param last size of counting range + * @return the return value of boost::counting_range + */ +template +auto counting_range(ValueT last) { + return boost::counting_range(ValueT{}, last); +} + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_COUNTING_RANGE_HPP_ */ diff --git a/include/cpp-utility/cpu.hpp b/include/cpp-utility/cpu.hpp new file mode 100644 index 0000000..624033a --- /dev/null +++ b/include/cpp-utility/cpu.hpp @@ -0,0 +1,94 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file cpu.hpp +* \brief Utilities to set CPU affinity +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_CPU_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_CPU_HPP_ + +#include +#include + +#include "bit.hpp" + +#if defined(_WIN32) +// Unfortunately, Boost.WinAPI does not declare SetThreadAffinityMask. +#include +#elif defined(__APPLE__) +#ifndef _DARWIN_C_SOURCE +#error _DARWIN_C_SOURCE must be defined +#endif +#include +#include +#include +#else +#ifndef _GNU_SOURCE +#error _GNU_SOURCE must be defined +#endif +#include +#endif + +namespace caen { + +namespace cpu { + +inline void set_current_thread_affinity(int cpu_id) { +#if defined(_WIN32) + const auto current_thread = ::GetCurrentThread(); + const auto mask = caen::bit::get_bit<::DWORD_PTR>(cpu_id); + const auto r = ::SetThreadAffinityMask(current_thread, mask); + if (r == 0) + throw std::runtime_error("SetThreadAffinityMask failed"); +#elif defined(__APPLE__) + ::thread_affinity_policy_data_t policy = { cpu_id }; + const auto current_thread = ::mach_thread_self(); + const auto r = ::thread_policy_set(current_thread, THREAD_AFFINITY_POLICY, reinterpret_cast<::thread_policy_t>(&policy), THREAD_AFFINITY_POLICY_COUNT); + if (r == KERN_SUCCESS) + throw std::runtime_error("thread_policy_set failed"); +#else + ::cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(cpu_id, &cpuset); + const auto current_thread = ::pthread_self(); + const auto r = ::pthread_setaffinity_np(current_thread, sizeof(cpuset), &cpuset); + if (r != 0) + throw std::runtime_error("pthread_setaffinity_np failed"); +#endif +} + +} // namespace cpu + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_CPU_HPP_ */ diff --git a/include/cpp-utility/dependent_false.hpp b/include/cpp-utility/dependent_false.hpp new file mode 100644 index 0000000..bb23d1c --- /dev/null +++ b/include/cpp-utility/dependent_false.hpp @@ -0,0 +1,54 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file dependent_false.hpp +* \brief Dependent false, utility for if-constexpr +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_DEPENDENT_FALSE_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_DEPENDENT_FALSE_HPP_ + +#include + +namespace caen { + +/* + * @brief Utility to use static_assert on if-constexpr. + * + * @sa https://stackoverflow.com/a/14637534/3287591 + */ +template +struct dependent_false : std::false_type {}; + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_DEPENDENT_FALSE_HPP_ */ diff --git a/include/cpp-utility/dll.hpp b/include/cpp-utility/dll.hpp new file mode 100644 index 0000000..935d7aa --- /dev/null +++ b/include/cpp-utility/dll.hpp @@ -0,0 +1,152 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file dll.hpp +* \brief Load library utils (Boost.DLL would be fine but, until 1.70, it required Boost.Filesystem that is not header-only) +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_DLL_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_DLL_HPP_ + +#include +#include + +#include + +#include + +#if BOOST_OS_WINDOWS +#include +#include +#include +#else +#include +#endif + +#include "string_view.hpp" + +namespace caen { + +namespace dll { + +using namespace std::literals; + +namespace detail { +#if BOOST_OS_WINDOWS +inline std::string windows_get_last_error() { + const auto id = boost::winapi::GetLastError(); + const auto ec = std::system_category().default_error_condition(id); + return fmt::format("{} error: {} ({})", ec.category().name(), ec.message(), ec.value()); +} +#endif +} // namespace detail + +struct dll { + +#if BOOST_OS_WINDOWS + using handle_t = boost::winapi::HMODULE_; +#else + using handle_t = void*; +#endif + + dll(caen::string_view name) + : _path(get_library_name(name)) + , _h{load_library(_path)} {} + + ~dll() try { + close_library(_h); + } catch (...) { + // suppress exception + return; + } + + template + FunctionType f(caen::string_view api_name) const { + FunctionType p; +#if BOOST_OS_WINDOWS + p = reinterpret_cast(boost::winapi::get_proc_address(_h, api_name.data())); + if (p == nullptr) + throw std::runtime_error(fmt::format("GetProcAddress failed: {}", detail::windows_get_last_error())); +#else + // error detection based on https://linux.die.net/man/3/dlsym + ::dlerror(); + p = reinterpret_cast(::dlsym(_h, api_name.data())); + const auto msg = ::dlerror(); + if (msg != nullptr) + throw std::runtime_error(fmt::format("dlsym failed: {}", msg)); +#endif + return p; + } + +private: + + static void close_library(handle_t handle) { +#if BOOST_OS_WINDOWS + if (boost::winapi::FreeLibrary(handle) == 0) + throw std::runtime_error(fmt::format("FreeLibrary failed: {}", detail::windows_get_last_error())); +#else + if (::dlclose(handle) != 0) + throw std::runtime_error(fmt::format("dlclose failed: {}", ::dlerror())); +#endif + } + + static handle_t load_library(caen::string_view library_name) { + handle_t p; +#if BOOST_OS_WINDOWS + p = boost::winapi::load_library(library_name.data()); + if (p == nullptr) + throw std::runtime_error(fmt::format("LoadLibrary failed: {}", detail::windows_get_last_error())); +#else + p = ::dlopen(library_name.data(), RTLD_NOW); + if (p == nullptr) + throw std::runtime_error(fmt::format("dlopen failed: {}", ::dlerror())); +#endif + return p; + } + + static std::string get_library_name(caen::string_view name) { +#if BOOST_OS_WINDOWS + return fmt::format("{}.dll", name); +#else + return fmt::format("lib{}.so", name); +#endif + } + + const std::string _path; + const handle_t _h; +}; + +} // namespace dll + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_DLL_HPP_ */ diff --git a/include/cpp-utility/hash.hpp b/include/cpp-utility/hash.hpp new file mode 100644 index 0000000..41bac4d --- /dev/null +++ b/include/cpp-utility/hash.hpp @@ -0,0 +1,386 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file hash.hpp +* \brief Compile time string hash +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_HASH_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_HASH_HPP_ + +#include +#include +#include +#include +#include + +#include +#include + +#if BOOST_PREDEF_WORKAROUND(BOOST_COMP_MSVC, <, 19, 24, 0) +/* + * Visual Studio emits a false warning; fixed on MSVC2019 16.4 (_MSC_VER == 1924). + * See https://developercommunity.visualstudio.com/t/unsigned-integer-overflows-in-constexpr-functionsa/211134 + */ +#pragma warning(push) +#pragma warning(disable: 4307) +#endif + +namespace caen { + +namespace hash { + +namespace detail { + +/** + * @brief Algorithm agnostic class to be uses using CRTP idiom. + */ +template +struct base_hash_generator { + // requirements + static_assert(std::is_unsigned::value, "UIntT must be an unsigned integral type"); + // base operator that stops just before the first null terminator + template + constexpr UIntT operator()(const CharT* data) const noexcept { + return hash(Impl::offset_basis, data); + } + // base operator, no dereferences if size == 0 (null terminators processed if found) + template + constexpr UIntT operator()(const CharT* data, std::size_t size) const noexcept { + return hash(Impl::offset_basis, data, size); + } + // base operator for nullptr, no dereferences if size == 0 + constexpr UIntT operator()(std::nullptr_t data, std::size_t size) const noexcept { + return operator()(data, size); + } + // base operator, no dereferences if begin == end (null terminators processed if found) + template + constexpr UIntT operator()(It begin, It end) const { + return hash(Impl::offset_basis, begin, end); + } + // operator wrapper for containers, strings and string views (null terminators processed if found) + // SFINAE required to select `const CharT*` overload when argument is `CharT*` or `CharT[]` + template ::value || std::is_array::value), int> = 0> + constexpr UIntT operator()(const T& c) const { + return operator()(std::begin(c), std::end(c)); + } +private: + // hash function that stops just before the first null terminator + template + constexpr UIntT hash(UIntT value, const CharT* data) const noexcept { + while (*data != '\0') + value = Impl::char_hash(value, *data++); + return value; + } + // hash function, no dereferences if size == 0 (null terminators processed if found) + template + constexpr UIntT hash(UIntT value, const CharT* data, std::size_t size) const noexcept { + for (; size != 0; --size) + value = Impl::char_hash(value, *data++); + return value; + } + // hash function, no dereferences if begin == end (null terminators processed if found) + template + constexpr UIntT hash(UIntT value, It begin, It end) const { + while (begin != end) + value = Impl::char_hash(value, *begin++); + return value; + } +}; + +/** + * @brief Hash using xor followed by product. + * + * Implemented using `prime * (value ^ data)`. + */ +template +struct xor_product_impl : base_hash_generator, UIntT> { + static constexpr UIntT offset_basis{OffsetBasis}; + static constexpr UIntT prime{Prime}; + template static constexpr UIntT char_hash(UIntT value, CharT data) noexcept { return prime * (value ^ data); } +}; + +/** + * @brief Hash using product followed by xor. + * + * Implemented using `(prime * value) ^ data`. + */ +template +struct product_xor_impl : base_hash_generator, UIntT> { + static constexpr UIntT offset_basis{OffsetBasis}; + static constexpr UIntT prime{Prime}; + template static constexpr UIntT char_hash(UIntT value, CharT data) noexcept { return (prime * value) ^ data; } +}; + +/** + * @brief Hash using product followed by sum. + * + * Implemented using `(prime * value) + data`. + */ +template +struct product_sum_impl : base_hash_generator, UIntT> { + static constexpr UIntT offset_basis{OffsetBasis}; + static constexpr UIntT prime{Prime}; + template static constexpr UIntT char_hash(UIntT value, CharT data) noexcept { return (prime * value) + data; } +}; + +/** +* @defgroup HashAlgorithms Hash algorithm +* @brief Hash algorithms that can be easily implemented with xor+product, product+xor and product+sum. +* +* Definition of every known and documented hash algorithms that can be implemented +* using one of @ref xor_product_impl, @ref product_xor_impl and @ref product_sum_impl. +* +* @{ */ +using fnv0_32 = product_xor_impl; //!< 32-bit FNV-0. @warning Not good, used only to compute FNV-1 offset basis. +using fnv0_64 = product_xor_impl; //!< 64-bit FNV-0. @warning Not good, used only to compute FNV-1 offset basis. +using fnv1_32 = product_xor_impl; //!< 32-bit FNV-1. +using fnv1_64 = product_xor_impl; //!< 64-bit FNV-1. +using fnv1a_32 = xor_product_impl; //!< 32-bit FNV-1a. +using fnv1a_64 = xor_product_impl; //!< 64-bit FNV-1a. +using djb2 = product_sum_impl; //!< 32-bit DJB2. +using djb2a = product_xor_impl; //!< 32-bit DJB2a. +using sdbm = product_sum_impl; //!< 32-bit SDBM hash algorithm. +using lose_lose = product_sum_impl; //!< 32-bit lose-lose from K&R (1st ed). @warning Extremely simple, terrible hashing. +/** @} */ + +namespace sanity_checks { + +namespace detail { + +template +constexpr bool hello_word_consistency(Args&&... args) noexcept { + // sanity checks with hello world of CharT type + bool ret{true}; + ret &= (fnv1_32{}(std::forward(args)...) == std::uint32_t{0x548da96f}); + ret &= (fnv1_64{}(std::forward(args)...) == std::uint64_t{0x7dcf62cdb1910e6f}); + ret &= (fnv1a_32{}(std::forward(args)...) == std::uint32_t{0xd58b3fa7}); + ret &= (fnv1a_64{}(std::forward(args)...) == std::uint64_t{0x779a65e7023cd2e7}); + ret &= (djb2{}(std::forward(args)...) == std::uint32_t{0x3551c8c1}); + ret &= (djb2a{}(std::forward(args)...) == std::uint32_t{0xf8c65345}); + ret &= (sdbm{}(std::forward(args)...) == std::uint32_t{0x19ae84c4}); + ret &= (lose_lose{}(std::forward(args)...) == std::uint32_t{0x45c}); + return ret; +} + +} // namespace detail + +constexpr bool test_hash_utils_1() noexcept { + // sanity checks for FNV-1 offset basis + // see http://www.isthe.com/chongo/tech/comp/fnv/index.html + bool ret{true}; + const char chongo[] = R"(chongo /\../\)"; + ret &= (fnv0_32{}(chongo) == fnv1_32::offset_basis); + ret &= (fnv0_64{}(chongo) == fnv1_64::offset_basis); + return ret; +} +constexpr bool test_hash_utils_2() noexcept { + // sanity checks with strings known to provide null hash + // see http://www.isthe.com/chongo/tech/comp/fnv/index.html + bool ret{true}; + ret &= (!fnv1_32{}("ba,1q")); + ret &= (!fnv1_32{}("T u{[")); + ret &= (!fnv1_32{}("03SB[")); + ret &= (!fnv1_64{}("!v)EYwYVk&")); + ret &= (!fnv1_64{}("Mt5Kexny31n")); + ret &= (!fnv1_64{}("OjSHjikPNYV")); + ret &= (!fnv1_64{}("YIA9YWMOARX")); + ret &= (!fnv1a_32{}("eSN.1")); + ret &= (!fnv1a_32{}("68m* ")); + ret &= (!fnv1a_32{}("+!=yG")); + ret &= (!fnv1a_64{}("!0IC=VloaY")); + ret &= (!fnv1a_64{}("QvXtM>@Fp%")); + ret &= (!fnv1a_64{}("77kepQFQ8Kl")); + return ret; +} +constexpr bool test_hash_utils_3() noexcept { + // sanity checks for known collisions + // see https://softwareengineering.stackexchange.com/q/49550 + bool ret{true}; + ret &= (fnv1_32{}("creamwove") == fnv1_32{}("quists")); + ret &= (fnv1a_32{}("costarring") == fnv1a_32{}("liquid")); + ret &= (fnv1a_32{}("declinate") == fnv1a_32{}("macallums")); + ret &= (fnv1a_32{}("altarage") == fnv1a_32{}("zinke")); + ret &= (djb2{}("ar") == djb2{}("c0")); + ret &= (djb2{}("hetairas") == djb2{}("mentioner")); + ret &= (djb2{}("heliotropes") == djb2{}("neurospora")); + ret &= (djb2{}("depravement") == djb2{}("serafins")); + ret &= (djb2{}("stylist") == djb2{}("subgenera")); + ret &= (djb2{}("joyful") == djb2{}("synaphea")); + ret &= (djb2{}("redescribed") == djb2{}("urites")); + ret &= (djb2{}("dram") == djb2{}("vivency")); + ret &= (djb2{}("appling") == djb2{}("bedaggle")); + ret &= (djb2{}("broadened") == djb2{}("kilohm")); + ret &= (djb2a{}("haggadot") == djb2a{}("loathsomenesses")); + ret &= (djb2a{}("playwright") == djb2a{}("snush")); + ret &= (djb2a{}("adorablenesses") == djb2a{}("rentability")); + ret &= (djb2a{}("treponematoses") == djb2a{}("waterbeds")); + return ret; +} +constexpr bool test_hash_utils_4() noexcept { + // sanity checks with hello world of various character types + char non_const_array[] = "hello world"; + bool ret{true}; + ret &= (detail::hello_word_consistency("hello world")); + ret &= (detail::hello_word_consistency(u8"hello world")); + ret &= (detail::hello_word_consistency(L"hello world")); + ret &= (detail::hello_word_consistency(u"hello world")); + ret &= (detail::hello_word_consistency(U"hello world")); + ret &= (detail::hello_word_consistency(non_const_array)); + ret &= (detail::hello_word_consistency(static_cast(non_const_array))); + ret &= (detail::hello_word_consistency(non_const_array, 11)); + ret &= (!detail::hello_word_consistency(non_const_array, 12)); + ret &= (!detail::hello_word_consistency("hello world long")); + ret &= (!detail::hello_word_consistency("hello world long", 10)); + ret &= (detail::hello_word_consistency("hello world long", 11)); + ret &= (!detail::hello_word_consistency("hello world long", 12)); + return ret; +} +constexpr bool test_hash_utils_5() noexcept { + // sanity checks for empty strings + bool ret{true}; + const char empty[] = ""; + ret &= (fnv0_32{}(empty) == fnv0_32::offset_basis); + ret &= (fnv0_64{}(empty) == fnv0_64::offset_basis); + ret &= (fnv1_32{}(empty) == fnv1_32::offset_basis); + ret &= (fnv1_64{}(empty) == fnv1_64::offset_basis); + ret &= (fnv1a_32{}(empty) == fnv1a_32::offset_basis); + ret &= (fnv1a_64{}(empty) == fnv1a_64::offset_basis); + ret &= (djb2{}(empty) == djb2::offset_basis); + ret &= (djb2a{}(empty) == djb2a::offset_basis); + ret &= (sdbm{}(empty) == sdbm::offset_basis); + ret &= (lose_lose{}(empty) == lose_lose::offset_basis); + return ret; +} +constexpr bool test_hash_utils_6() noexcept { + // sanity checks for null pointers with zero size (no dereferences using hash) + bool ret{true}; + ret &= (fnv0_32{}(nullptr, 0) == fnv0_32::offset_basis); + ret &= (fnv0_64{}(nullptr, 0) == fnv0_64::offset_basis); + ret &= (fnv1_32{}(nullptr, 0) == fnv1_32::offset_basis); + ret &= (fnv1_64{}(nullptr, 0) == fnv1_64::offset_basis); + ret &= (fnv1a_32{}(nullptr, 0) == fnv1a_32::offset_basis); + ret &= (fnv1a_64{}(nullptr, 0) == fnv1a_64::offset_basis); + ret &= (djb2{}(nullptr, 0) == djb2::offset_basis); + ret &= (djb2a{}(nullptr, 0) == djb2a::offset_basis); + ret &= (sdbm{}(nullptr, 0) == sdbm::offset_basis); + ret &= (lose_lose{}(nullptr, 0) == lose_lose::offset_basis); + return ret; +} + +static_assert(test_hash_utils_1(), "inconsistent hash implementation"); +static_assert(test_hash_utils_2(), "inconsistent hash implementation"); +static_assert(test_hash_utils_3(), "inconsistent hash implementation"); +static_assert(test_hash_utils_4(), "inconsistent hash implementation"); +static_assert(test_hash_utils_5(), "inconsistent hash implementation"); +static_assert(test_hash_utils_6(), "inconsistent hash implementation"); + +} // namespace sanity_checks + +} // namespace detail + +// imported into hash namespace +using detail::fnv1_32; +using detail::fnv1_64; +using detail::fnv1a_32; +using detail::fnv1a_64; +using detail::djb2; +using detail::djb2a; +using detail::sdbm; +using detail::lose_lose; + +using generator = fnv1a_64; //!< Set default hash generator for string to @ref caen::hash::detail::fnv1a_64 +using default_hash_generator = generator; //!< Legacy alias + +namespace literals { + +/** + * @brief UDL to convert string literal to hash using @ref caen::hash::generator. + * + * @return hash of input string + */ +constexpr auto operator""_h(const char* data, std::size_t size) noexcept { + return generator{}(data, size); +} + +/** + * @brief UDL to convert wide string literals to hash using @ref caen::hash::generator. + * + * @return hash of input string + */ +constexpr auto operator""_h(const wchar_t* data, std::size_t size) noexcept { + return generator{}(data, size); +} + +namespace sanity_checks { + +namespace detail { + +enum class switch_output { a, b, other }; + +constexpr switch_output hash_utils_switch(const char *str) noexcept { + switch (generator{}(str)) { + case "a"_h: return switch_output::a; + case "b"_h: return switch_output::b; + default: return switch_output::other; + } +} + +} // namespace detail + +constexpr bool test_hash_utils_literals() noexcept { + bool ret{true}; + ret &= (detail::hash_utils_switch("a") == detail::switch_output::a); + ret &= (detail::hash_utils_switch("b") == detail::switch_output::b); + ret &= (detail::hash_utils_switch("c") == detail::switch_output::other); + ret &= ("hello world"_h == generator{}("hello world")); + ret &= (L"hello world"_h == generator{}(L"hello world")); + ret &= (""_h == generator{}("")); + ret &= (L""_h == generator{}(L"")); + return ret; +} + +static_assert(test_hash_utils_literals(), "inconsistent literal implementation"); + +} // namespace sanity_checks + +} // namespace literals + +} // namespace hash + +} // namespace caen + +#if BOOST_PREDEF_WORKAROUND(BOOST_COMP_MSVC, <, 19, 24, 0) +#pragma warning(pop) +#endif + +#endif /* CAEN_INCLUDE_CPP_UTILITY_HASH_HPP_ */ diff --git a/include/cpp-utility/iequals.hpp b/include/cpp-utility/iequals.hpp new file mode 100644 index 0000000..7f3a493 --- /dev/null +++ b/include/cpp-utility/iequals.hpp @@ -0,0 +1,49 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file iequals.hpp +* \brief Legacy include, to be replaced with string.hpp +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_IEQUALS_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_IEQUALS_HPP_ + +#include "string.hpp" + +namespace caen { + +// import also into caen namespace +using string::iequals; + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_IEQUALS_HPP_ */ diff --git a/include/cpp-utility/integer.hpp b/include/cpp-utility/integer.hpp new file mode 100644 index 0000000..e52f5bf --- /dev/null +++ b/include/cpp-utility/integer.hpp @@ -0,0 +1,95 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file integer.hpp +* \brief Boost.Integer with fast type specialization from cstdint +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_INTEGER_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_INTEGER_HPP_ + +#include + +#include + +#ifndef CAEN_NO_BOOST_INT_SPECIALIZATION + +/* + * From `boost::int_fast_t` documentation: + * + * > By default, the output type is identical to the input type. Eventually, + * > this code's implementation should be customized for each platform to give + * > accurate mappings between the built-in types and the easiest-to-manipulate + * > built-in types. Also, there is no guarantee that the output type actually + * > is easier to manipulate than the input type. + * + * We implement those specializations relying on cstdint types. Usually, main + * differences are that 16-bit types are replaced by larger types and, at least + * on Linux, 32-bit types are replaced by 64-bit types, if compiling for 64-bit + * architectures. + * + * Important: + * Template specializations must be defined before any instantiation. Some Boost + * libraries, like Boost.Lexical_Cast, use Boost.Integer: compilation fails if + * their headers are included before this header. This is why we provide a way + * to compile out this part in case you are fine with the default implementation + * of `boost::int_fast_t`: define CAEN_NO_BOOST_INT_SPECIALIZATION at compile + * time. In this case, the default implementation will be used. + */ +namespace boost { + +template<> struct int_fast_t { using type = std::uint_fast8_t; }; +template<> struct int_fast_t { using type = std::uint_fast16_t; }; +template<> struct int_fast_t { using type = std::uint_fast32_t; }; +template<> struct int_fast_t { using type = std::uint_fast64_t; }; +template<> struct int_fast_t { using type = std::int_fast8_t; }; +template<> struct int_fast_t { using type = std::int_fast16_t; }; +template<> struct int_fast_t { using type = std::int_fast32_t; }; +template<> struct int_fast_t { using type = std::int_fast64_t; }; + +} // namespace boost + +#endif + +namespace caen { + +// prefer caen namespace to be sure specializations in this header are used + +using boost::uint_t; +using boost::int_t; +using boost::int_min_value_t; +using boost::int_max_value_t; +using boost::uint_value_t; + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_INTEGER_HPP_ */ diff --git a/include/cpp-utility/is_in.hpp b/include/cpp-utility/is_in.hpp new file mode 100644 index 0000000..ceff6b1 --- /dev/null +++ b/include/cpp-utility/is_in.hpp @@ -0,0 +1,152 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file is_in.hpp +* \brief Utilities to compare groups of values +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_IS_IN_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_IS_IN_HPP_ + +#include + +namespace caen { + +#if __cplusplus < 201703L +inline +#endif +namespace pre_cxx17 { + +/** + * @brief Check if a variable is equal to all variables in a given set. + * + * @tparam T value type + * @tparam Args parameter pack + * @param value the value + * @param args values to be compared with value + * @return true if value is equal to all in args + */ +template +constexpr bool are_equals(const T& value, const Args&... args) noexcept { + static_assert(sizeof...(args) > 0, "at least one value is needed"); + bool ret = true; + using unused = bool[]; + (void)(unused{ false, ret &= value == args... }); + return ret; +} + +/** + * @brief Check if a variable is equal to any variables in a given set. + * + * @tparam T value type + * @tparam Args parameter pack + * @param value the value + * @param args values to be compared with value + * @return true if value is equal to any in args + */ +template +constexpr bool is_in(const T& value, const Args&... args) noexcept { + static_assert(sizeof...(args) > 0, "at least one value is needed"); + bool ret = false; + using unused = bool[]; + (void)(unused{ false, ret |= value == args... }); + return ret; +} + +} // namespace pre_cxx17 + +#if __cplusplus >= 201703L +inline namespace cxx17 { + +/** + * @brief Check if a variable is equal to any variables in a given set. + * + * @tparam T value type + * @tparam Args parameter pack + * @param value the value + * @param args values to be compared with value + * @return true if value is equal to any in args + */ +template +constexpr bool is_in(const T& value, const Args&... args) noexcept { + static_assert(sizeof...(args) > 0, "at least one value is needed"); + return ((value == args) || ...); +} + + +/** + * @brief Check if a variable is equal to all variables in a given set. + * + * @tparam T value type + * @tparam Args parameter pack + * @param value the value + * @param args values to be compared with value + * @return true if value is equal to all in args + */ +template +constexpr bool are_equals(const T& value, const Args&... args) { + static_assert(sizeof...(args) > 0, "at least one value is needed"); + return ((value == args) && ...); +} + +} // namespace cxx17 + +#endif + +namespace sanity_checks { + +constexpr bool test_is_in() noexcept { + bool ret{true}; + ret &= is_in(1, 1); + ret &= !is_in(0, 1); + ret &= is_in(1, 1, 2, 3, 4); + ret &= !is_in(1, 10); + return ret; +} + +constexpr bool test_are_equals() noexcept { + bool ret{true}; + ret &= are_equals(1, 1); + ret &= !are_equals(0, 1); + ret &= are_equals(1, 1, 1, 1, 1); + ret &= !are_equals(1, 10); + return ret; +} + +BOOST_STATIC_ASSERT(test_is_in()); +BOOST_STATIC_ASSERT(test_are_equals()); + +} // namespace sanity_checks + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_IS_IN_HPP_ */ diff --git a/include/cpp-utility/lexical_cast.hpp b/include/cpp-utility/lexical_cast.hpp new file mode 100644 index 0000000..3cf6a20 --- /dev/null +++ b/include/cpp-utility/lexical_cast.hpp @@ -0,0 +1,213 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file lexical_cast.hpp +* \brief Utilities related to `boost::lexical_cast` +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_LEXICAL_CAST_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_LEXICAL_CAST_HPP_ + +#include +#include + +// see comment on integer.hpp for rationale of this useless include +#include "integer.hpp" + +#include +#include +#include + +#include "type_traits.hpp" + +namespace caen { + +namespace conversion { + +namespace detail { + +template +struct is_char : is_type_any_of {}; + +template +struct no_char : negation, is_char>> {}; + +template +struct is_char_target : conjunction, negation>> {}; + +template +struct is_char_source : conjunction>, is_char> {}; + +template +struct is_char_both : conjunction, is_char> {}; + +template struct intermediate_impl {}; // default case (compile time error) +template <> struct intermediate_impl { using type = signed int; }; +template <> struct intermediate_impl { using type = unsigned int; }; + +template +struct intermediate : intermediate_impl> {}; + +template +using intermediate_t = typename intermediate::type; + +namespace sanity_check { + +constexpr bool test_is_char() noexcept { + bool ret{true}; + ret &= (!is_char::value); + ret &= (is_char::value); + ret &= (is_char::value); + ret &= (!is_char::value); + ret &= (is_char::value); + ret &= (is_char::value); + ret &= (!is_char::value); + ret &= (is_char::value); + ret &= (is_char::value); + ret &= (!is_char::value); + ret &= (is_char::value); + ret &= (is_char::value); + return ret; +} + +constexpr bool test_is_char_target_or_source() noexcept { + bool ret{true}; + ret &= (no_char::value); + ret &= (!no_char::value); + ret &= (is_char_target::value); + ret &= (!is_char_target::value); + ret &= (is_char_source::value); + ret &= (!is_char_source::value); + ret &= (is_char_both::value); + ret &= (!is_char_both::value); + return ret; +} + +constexpr bool test_intermediate() noexcept { + bool ret{true}; + ret &= (std::is_same, signed int>::value); + ret &= (std::is_same, unsigned int>::value); + return ret; +} + +BOOST_STATIC_ASSERT(test_is_char()); +BOOST_STATIC_ASSERT(test_is_char_target_or_source()); +BOOST_STATIC_ASSERT(test_intermediate()); + +} // namespace sanity_check + +template ::value, int> = 0> +decltype(auto) lexical_cast(const Source& arg) { + // standard case + return boost::lexical_cast(arg); +} + +template ::value, int> = 0> +decltype(auto) lexical_cast(const Source& arg) { + // intermediate result to int, then numeric_cast to throw if overflows target + const auto int_res = boost::lexical_cast>(arg); + return boost::numeric_cast(int_res); +} + +template ::value, int> = 0> +decltype(auto) lexical_cast(const Source& arg) { + // intermediate source to int: would fail at compile time only if intermediate_t{arg} would be a narrowing conversion + return boost::lexical_cast(intermediate_t{arg}); +} + +template ::value, int> = 0> +decltype(auto) lexical_cast(const Source& arg) { + // strange case, a mix of the two previous cases: numeric_cast could be sufficient, lexical_cast kept for consistency + const auto int_res = boost::lexical_cast>(intermediate_t{arg}); + return boost::numeric_cast(arg); +} + +template ::value, int> = 0> +decltype(auto) lexical_cast(const CharT* size, std::size_t count) { + // standard case + return boost::lexical_cast(size, count); +} + +template ::value, int> = 0> +decltype(auto) lexical_cast(const CharT* size, std::size_t count) { + // intermediate result to int, then numeric_cast to throw if overflows target + const auto int_res = boost::lexical_cast>(size, count); + return boost::numeric_cast(int_res); +} + +} // namespace detail + +/** + * @brief Same of `boost::lexical_cast`, except that `signed char` and `unsigned char` are treated as integer types. + * + * `boost::lexical_cast` treats `signed char` and `unsigned char` just like + * `char`, both as input and output type. This could be undesirable and not + * intuitive at all: we add a wrapper to add intermediate conversions to integers + * when dealing with `signed char` and `unsigned char`, using `boost::numeric_cast` + * to throw in case of overflows. + * Note that this hack has effect also on `std::int8_t` and `std::uint8_t`, + * typically implemented as typedef to these types. + * @warning String to number with base detection is not supported. Use `caen::string::to_number()` if required. + * @warning The behavior of this function depends on the current global C++ locale. + * @sa https://www.boost.org/doc/libs/1_67_0/doc/html/boost_lexical_cast/frequently_asked_questions.html + * @tparam Target output type + * @tparam Args parameter pack forwarded to `boost::lexical_cast` + * @param[in] args parameter pack name + * @return a variable of Target type + */ +template +decltype(auto) lexical_cast(Args&& ...args) { + return detail::lexical_cast(std::forward(args)...); +} + +/** + * @brief Convenience function for template argument deduction. + * + * @tparam Target the output type, that can be deduced from argument + * @tparam Args parameter pack forwarded to `caen::conversion::lexical_cast()` + * @param[out] result the output + * @param[in] args parameter pack name + */ +template +void lexical_cast_to(Target& result, Args&& ...args) { + result = lexical_cast(std::forward(args)...); +} + +} // namespace conversion + +// import also into caen namespace +using conversion::lexical_cast; +using conversion::lexical_cast_to; + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_LEXICAL_CAST_HPP_ */ diff --git a/include/cpp-utility/math.hpp b/include/cpp-utility/math.hpp new file mode 100644 index 0000000..8d0901f --- /dev/null +++ b/include/cpp-utility/math.hpp @@ -0,0 +1,443 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file math.hpp +* \brief Math utils +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_MATH_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_MATH_HPP_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "type_traits.hpp" + +namespace caen { + +namespace math { + +namespace detail { + +template ::value, int> = 0> +Int round_impl(Float v) noexcept { + return static_cast(v + Float{0.5}); +} +template ::value, int> = 0> +Int round_impl(Float v) { + return static_cast(std::lround(v)); +} +template ::value, int> = 0> +Int round_impl(Float v) { + return std::lround(v); +} +template ::value, int> = 0> +Int round_impl(Float v) { + return std::llround(v); +} + +template +Int round(Float v) { + if (v < std::numeric_limits::lowest() || v > std::numeric_limits::max()) + throw std::out_of_range("invalid range"); + return round_impl(v); +} + +} // namespace detail + +/* + * cmath constexpr functions are a GCC extension. + * Moreover, its support is limited on GCC 5 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67371) + */ +#if BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(6, 1, 0) +#define CAEN_MATH_CONSTEXPR_SUPPORTED +#define CAEN_MATH_CONSTEXPR constexpr +#else +#define CAEN_MATH_CONSTEXPR +#endif + +// generic case for floating point +template ::value, int> = 0> +CAEN_MATH_CONSTEXPR bool is_zero(T v) noexcept { + return std::abs(v) < std::numeric_limits::epsilon() * T{1e5}; // 1e5 is an arbitrary tolerance factor +} + +// special case for integers where epsilon() == 0 +template ::value, int> = 0> +constexpr bool is_zero(T v) noexcept { + return v == T{}; +} + +template ::value, int> = 0> +constexpr bool is_negative(T v) noexcept { + return v < T{}; +} + +template ::value, int> = 0> +constexpr bool is_negative(T v) noexcept { + boost::ignore_unused(v); + return false; +} + +template +CAEN_MATH_CONSTEXPR bool is_aligned(T v, T step) noexcept { + return is_zero(std::remainder(v, step)); +} + +template +CAEN_MATH_CONSTEXPR T distance_from_nearest_unit(T v) noexcept { + static_assert(std::is_floating_point::value, "input type must be floating point number"); + return std::abs(std::remainder(v, 1.)); +} + +template +CAEN_MATH_CONSTEXPR unsigned int digits_after_decimal_point(T v, unsigned int base = 10, T tolerance = 4.) { + static_assert(std::is_floating_point::value, "input type must be floating point number"); + switch (std::fpclassify(v)) { + case FP_ZERO: + return 0; + case FP_NORMAL: { + unsigned int n{}; + T eps{tolerance * std::abs(v) * std::numeric_limits::epsilon()}; + while (distance_from_nearest_unit(v) > eps) { + v *= base; + eps *= base; + ++n; + } + return n; + } + case FP_SUBNORMAL: + case FP_NAN: + case FP_INFINITE: + default: + throw std::domain_error("invalid value"); + } +} + +template +CAEN_MATH_CONSTEXPR T round_to_nearest_multiple_of(T v, T multiple) { + if (is_negative(multiple)) { + throw std::domain_error("multiple cannot be negative"); + } else if (is_zero(multiple)) { + return v; + } + const auto ratio = static_cast(v) / multiple; + const auto iratio = static_cast(std::lround(ratio)); + return iratio * multiple; +} + +template > +constexpr UnsignedT abs(SignedT v) noexcept { + static_assert(std::is_integral::value, "input type must be integer"); + static_assert(std::is_signed::value, "input type must be signed"); + // see https://stackoverflow.com/a/16101699/3287591 +#if BOOST_COMP_MSVC +// Ignoring "unary minus operator applied to unsigned type, result still unsigned" +#pragma warning(push) +#pragma warning(disable: 4146) +#endif + return v >= 0 ? v : -static_cast(v); +#if BOOST_COMP_MSVC +#pragma warning(pop) +#endif +} + +/** + * @brief Safe round floating point numbers to integers. + * + * @tparam Int output integer type + * @tparam Float input floating point type + * @param[in] value input floating point + * @return the result of rounding + */ +template +Int round(Float value) { + static_assert(std::is_integral::value, "output type must be integer"); + static_assert(std::is_floating_point::value, "input type must be integer"); + return detail::round(value); +} + +/** + * @brief Convenience function for template argument deduction. + * + * @overload + */ +template +void round(Int& v, Float value) { + v = round(value); +} + +namespace sanity_checks { + +constexpr bool test_abs() noexcept { + bool ret{true}; + ret &= (abs(100) == 100U); + ret &= (abs(0) == 0U); + ret &= (abs(-100) == 100U); + return ret; +} + +BOOST_STATIC_ASSERT(test_abs()); + +#ifdef CAEN_MATH_CONSTEXPR_SUPPORTED + +constexpr bool test_is_aligned() noexcept { + bool ret{true}; + // tests for integral values + ret &= (is_aligned(1, 1)); + ret &= (is_aligned(2, 1)); + ret &= (!is_aligned(1, 2)); + // test for floating point values + ret &= (is_aligned(0., 1.)); + ret &= (is_aligned(1e0, 1.)); + ret &= (is_aligned(1e10, 1.)); + ret &= (is_aligned(-1e0, 1.)); + ret &= (is_aligned(-1e10, 1.)); + ret &= (!is_aligned(1e-1, 1.)); + ret &= (!is_aligned(1e-10, 1.)); + ret &= (is_aligned(1e0, 1e-3)); + ret &= (is_aligned(1e2, 1e-3)); + ret &= (is_aligned(-1e-3, 1e-3)); + ret &= (is_aligned(-1e2, 1e-3)); + ret &= (!is_aligned(1e-4, 1e-3)); + ret &= (!is_aligned(1e-7, 1e-3)); + ret &= (is_aligned(7e0, 7.)); + ret &= (is_aligned(7e10, 7.)); + ret &= (is_aligned(-7e0, 7.)); + ret &= (is_aligned(-7e10, 7.)); + ret &= (!is_aligned(7e-1, 7.)); + ret &= (!is_aligned(7e-10, 7.)); + ret &= (is_aligned(7e-1, 7e-2)); + ret &= (is_aligned(7e-10, 7e-20)); + ret &= (!is_aligned(0.5, 1.)); + ret &= (!is_aligned(std::numeric_limits::epsilon() * 1e5, 1.)); + // expected failures + ret &= (is_aligned(std::numeric_limits::min(), 1.)); // within tolerance + return ret; +} + +constexpr bool test_round_to_nearest_multiple_of() noexcept { + bool ret{true}; + ret &= (round_to_nearest_multiple_of(1, 3) == 0); + ret &= (round_to_nearest_multiple_of(3, 3) == 3); + ret &= (round_to_nearest_multiple_of(1, 2) == 2); + ret &= (round_to_nearest_multiple_of(1, 0) == 1); + ret &= (round_to_nearest_multiple_of(-1, 3) == 0); + ret &= (round_to_nearest_multiple_of(-3, 3) == -3); + ret &= (round_to_nearest_multiple_of(-1, 2) == -2); + ret &= (round_to_nearest_multiple_of(-1, 0) == -1); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" + ret &= (round_to_nearest_multiple_of(1., 0.) == 1.); + ret &= (round_to_nearest_multiple_of(10., 9.) == 9.); + ret &= (round_to_nearest_multiple_of(100., 9.) == 99.); +#pragma GCC diagnostic pop + return ret; +} + +constexpr bool test_digits_after_decimal_point() noexcept { + bool ret{true}; + ret &= (digits_after_decimal_point(0.) == 0); + ret &= (digits_after_decimal_point(1e-1) == 1); + ret &= (digits_after_decimal_point(1e-2) == 2); + ret &= (digits_after_decimal_point(1e-3) == 3); + ret &= (digits_after_decimal_point(1e-4) == 4); + ret &= (digits_after_decimal_point(1e-5) == 5); + ret &= (digits_after_decimal_point(1e-6) == 6); + ret &= (digits_after_decimal_point(1e-7) == 7); + ret &= (digits_after_decimal_point(1e-8) == 8); + ret &= (digits_after_decimal_point(1e-9) == 9); + ret &= (digits_after_decimal_point(1e-10) == 10); + ret &= (digits_after_decimal_point(1e-11) == 11); + ret &= (digits_after_decimal_point(1e-12) == 12); + ret &= (digits_after_decimal_point(1e-13) == 13); + ret &= (digits_after_decimal_point(1e-14) == 14); + ret &= (digits_after_decimal_point(1e-15) == 15); + ret &= (digits_after_decimal_point(1e-16) == 16); + ret &= (digits_after_decimal_point(1e-17) == 17); + ret &= (digits_after_decimal_point(1e-18) == 18); + ret &= (digits_after_decimal_point(1e-19) == 19); + ret &= (digits_after_decimal_point(1e-20) == 20); + ret &= (digits_after_decimal_point(1e-100) == 100); + ret &= (digits_after_decimal_point(1e-200) == 200); + ret &= (digits_after_decimal_point(1e-300) == 300); + ret &= (digits_after_decimal_point(-1e-1) == 1); + ret &= (digits_after_decimal_point(-1e-2) == 2); + ret &= (digits_after_decimal_point(-1e-3) == 3); + ret &= (digits_after_decimal_point(-1e-4) == 4); + ret &= (digits_after_decimal_point(-1e-5) == 5); + ret &= (digits_after_decimal_point(-1e-6) == 6); + ret &= (digits_after_decimal_point(-1e-7) == 7); + ret &= (digits_after_decimal_point(-1e-8) == 8); + ret &= (digits_after_decimal_point(-1e-9) == 9); + ret &= (digits_after_decimal_point(-1e-10) == 10); + ret &= (digits_after_decimal_point(-1e-11) == 11); + ret &= (digits_after_decimal_point(-1e-12) == 12); + ret &= (digits_after_decimal_point(-1e-13) == 13); + ret &= (digits_after_decimal_point(-1e-14) == 14); + ret &= (digits_after_decimal_point(-1e-15) == 15); + ret &= (digits_after_decimal_point(-1e-16) == 16); + ret &= (digits_after_decimal_point(-1e-17) == 17); + ret &= (digits_after_decimal_point(-1e-18) == 18); + ret &= (digits_after_decimal_point(-1e-19) == 19); + ret &= (digits_after_decimal_point(-1e-20) == 20); + ret &= (digits_after_decimal_point(-1e-100) == 100); + ret &= (digits_after_decimal_point(-1e-200) == 200); + ret &= (digits_after_decimal_point(-1e-300) == 300); + ret &= (digits_after_decimal_point(1e0) == 0); + ret &= (digits_after_decimal_point(1e1) == 0); + ret &= (digits_after_decimal_point(1e2) == 0); + ret &= (digits_after_decimal_point(1e3) == 0); + ret &= (digits_after_decimal_point(1e4) == 0); + ret &= (digits_after_decimal_point(1e5) == 0); + ret &= (digits_after_decimal_point(1e6) == 0); + ret &= (digits_after_decimal_point(1e7) == 0); + ret &= (digits_after_decimal_point(1e8) == 0); + ret &= (digits_after_decimal_point(1e9) == 0); + ret &= (digits_after_decimal_point(1e10) == 0); + ret &= (digits_after_decimal_point(1e11) == 0); + ret &= (digits_after_decimal_point(1e12) == 0); + ret &= (digits_after_decimal_point(1e13) == 0); + ret &= (digits_after_decimal_point(1e14) == 0); + ret &= (digits_after_decimal_point(1e15) == 0); + ret &= (digits_after_decimal_point(1e16) == 0); + ret &= (digits_after_decimal_point(1e100) == 0); + ret &= (digits_after_decimal_point(1e200) == 0); + ret &= (digits_after_decimal_point(1e300) == 0); + ret &= (digits_after_decimal_point(-1e0) == 0); + ret &= (digits_after_decimal_point(-1e1) == 0); + ret &= (digits_after_decimal_point(-1e2) == 0); + ret &= (digits_after_decimal_point(-1e3) == 0); + ret &= (digits_after_decimal_point(-1e4) == 0); + ret &= (digits_after_decimal_point(-1e5) == 0); + ret &= (digits_after_decimal_point(-1e6) == 0); + ret &= (digits_after_decimal_point(-1e7) == 0); + ret &= (digits_after_decimal_point(-1e8) == 0); + ret &= (digits_after_decimal_point(-1e9) == 0); + ret &= (digits_after_decimal_point(-1e10) == 0); + ret &= (digits_after_decimal_point(-1e11) == 0); + ret &= (digits_after_decimal_point(-1e12) == 0); + ret &= (digits_after_decimal_point(-1e13) == 0); + ret &= (digits_after_decimal_point(-1e14) == 0); + ret &= (digits_after_decimal_point(-1e15) == 0); + ret &= (digits_after_decimal_point(-1e16) == 0); + ret &= (digits_after_decimal_point(-1e100) == 0); + ret &= (digits_after_decimal_point(-1e200) == 0); + ret &= (digits_after_decimal_point(-1e300) == 0); + ret &= (digits_after_decimal_point(2.0) == 0); + ret &= (digits_after_decimal_point(2.1) == 1); + ret &= (digits_after_decimal_point(2.01) == 2); + ret &= (digits_after_decimal_point(2.001) == 3); + ret &= (digits_after_decimal_point(2.0001) == 4); + ret &= (digits_after_decimal_point(2.00001) == 5); + ret &= (digits_after_decimal_point(2.000001) == 6); + ret &= (digits_after_decimal_point(2.0000001) == 7); + ret &= (digits_after_decimal_point(-2.2) == 1); + ret &= (digits_after_decimal_point(-2.03) == 2); + ret &= (digits_after_decimal_point(-2.004) == 3); + ret &= (digits_after_decimal_point(-2.0005) == 4); + ret &= (digits_after_decimal_point(-2.00006) == 5); + ret &= (digits_after_decimal_point(-2.000007) == 6); + ret &= (digits_after_decimal_point(-2.0000008) == 7); + ret &= (digits_after_decimal_point(1.2) == 1); + ret &= (digits_after_decimal_point(1.03) == 2); + ret &= (digits_after_decimal_point(1.004) == 3); + ret &= (digits_after_decimal_point(1.0005) == 4); + ret &= (digits_after_decimal_point(1.00006) == 5); + ret &= (digits_after_decimal_point(1.000007) == 6); + ret &= (digits_after_decimal_point(1.0000008) == 7); + ret &= (digits_after_decimal_point(-0.2) == 1); + ret &= (digits_after_decimal_point(-0.03) == 2); + ret &= (digits_after_decimal_point(-0.004) == 3); + ret &= (digits_after_decimal_point(-0.0005) == 4); + ret &= (digits_after_decimal_point(-0.00006) == 5); + ret &= (digits_after_decimal_point(-0.000007) == 6); + ret &= (digits_after_decimal_point(-0.0000008) == 7); + ret &= (digits_after_decimal_point(0.200) == 1); + ret &= (digits_after_decimal_point(0.2300) == 2); + ret &= (digits_after_decimal_point(0.20400) == 3); + ret &= (digits_after_decimal_point(0.200500) == 4); + ret &= (digits_after_decimal_point(0.2000600) == 5); + ret &= (digits_after_decimal_point(0.20000700) == 6); + ret &= (digits_after_decimal_point(0.200000800) == 7); + ret &= (digits_after_decimal_point(1. + 1e-1) == 1); + ret &= (digits_after_decimal_point(1. + 1e-2) == 2); + ret &= (digits_after_decimal_point(1. + 1e-3) == 3); + ret &= (digits_after_decimal_point(1. + 1e-4) == 4); + ret &= (digits_after_decimal_point(1. + 1e-5) == 5); + ret &= (digits_after_decimal_point(1. + 1e-6) == 6); + ret &= (digits_after_decimal_point(1. + 1e-7) == 7); + ret &= (digits_after_decimal_point(1. + 1e-8) == 8); + ret &= (digits_after_decimal_point(1. + 1e-9) == 9); + ret &= (digits_after_decimal_point(1. + 1e-10) == 10); + ret &= (digits_after_decimal_point(1. + 1e-11) == 11); + ret &= (digits_after_decimal_point(1. + 1e-12) == 12); + ret &= (digits_after_decimal_point(1. + 1e-13) == 13); + ret &= (digits_after_decimal_point(1. + 1e-14) == 14); + ret &= (digits_after_decimal_point(1. + 1e-15) == 15); + // base 2 tests + ret &= (digits_after_decimal_point(0.0, 2) == 0); + ret &= (digits_after_decimal_point(1.0, 2) == 0); + ret &= (digits_after_decimal_point(0.5, 2) == 1); + ret &= (digits_after_decimal_point(1.5, 2) == 1); + ret &= (digits_after_decimal_point(0.25, 2) == 2); + ret &= (digits_after_decimal_point(1.25, 2) == 2); + ret &= (digits_after_decimal_point(0.125, 2) == 3); + ret &= (digits_after_decimal_point(1.125, 2) == 3); + // expected failures + ret &= (digits_after_decimal_point(1. + 1e-16) == 0); // 1. + 1e-16 == 1. + ret &= (digits_after_decimal_point(1. + 2e-16) == 0); // 1. + 2e-16 != 1. but within tolerance + return ret; +} + +BOOST_STATIC_ASSERT(test_is_aligned()); +BOOST_STATIC_ASSERT(test_round_to_nearest_multiple_of()); +BOOST_STATIC_ASSERT(test_digits_after_decimal_point()); + +#endif + +} // namespace sanity_checks + +} // namespace math + +} // namespace caen + +#undef CAEN_MATH_CONSTEXPR_SUPPORTED + +#endif /* CAEN_INCLUDE_CPP_UTILITY_MATH_HPP_ */ diff --git a/include/cpp-utility/optional.hpp b/include/cpp-utility/optional.hpp new file mode 100644 index 0000000..857bfd2 --- /dev/null +++ b/include/cpp-utility/optional.hpp @@ -0,0 +1,86 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file optional.hpp +* \brief `std::optional` replacement for C++14 +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_OPTIONAL_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_OPTIONAL_HPP_ + +#include + +#if __cplusplus >= 201703L +#include +#endif + +#include + +namespace caen { + +#if __cplusplus < 201703L +inline +#endif +namespace pre_cxx17 { + +using boost::optional; +using boost::make_optional; +using nullopt_t = boost::none_t; +const nullopt_t nullopt = boost::none; + +// to emulate returning emplace also on pre_cxx17 +template +decltype(auto) emplace(optional& target, Args&& ...args) { + return target.emplace(std::forward(args)...), target.value(); +} + +} // namespace pre_cxx17 + +#if __cplusplus >= 201703L +inline namespace cxx17 { + +using std::optional; +using std::make_optional; +using std::nullopt_t; +using std::nullopt; + +template +decltype(auto) emplace(optional& target, Args&& ...args) { + return target.emplace(std::forward(args)...); +} + +} // namespace cxx17 +#endif + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_OPTIONAL_HPP_ */ diff --git a/include/cpp-utility/scope_exit.hpp b/include/cpp-utility/scope_exit.hpp new file mode 100644 index 0000000..31881bf --- /dev/null +++ b/include/cpp-utility/scope_exit.hpp @@ -0,0 +1,68 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file scope_exit.hpp +* \brief Scope exit, inspired to TS v3 `std::experimental::scope_exit` +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_SCOPE_EXIT_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_SCOPE_EXIT_HPP_ + +#include + +namespace caen { + +struct scope_exit { + + template + explicit scope_exit(Function&& f) + : _f(std::forward(f)) {} + + scope_exit(scope_exit&& other) = default; + scope_exit(const scope_exit&) = delete; + + ~scope_exit() { + if (_f) + _f(); + } + + void release() noexcept { + _f = nullptr; + } + +private: + std::function _f; +}; + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_SCOPE_EXIT_HPP_ */ diff --git a/include/cpp-utility/scoped_set.hpp b/include/cpp-utility/scoped_set.hpp new file mode 100644 index 0000000..4a278e8 --- /dev/null +++ b/include/cpp-utility/scoped_set.hpp @@ -0,0 +1,95 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file scoped_set.hpp +* \brief Scoped set +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_SCOPED_SET_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_SCOPED_SET_HPP_ + +#include +#include + +#include "optional.hpp" + +namespace caen { + +template +class scoped_set { + + using value_type = T; + using reference = T&; + using const_reference = const T&; + + reference _variable; + optional _original_value; + +public: + + template + scoped_set(reference variable, Arg&& value) noexcept + : _variable{variable} + , _original_value{std::exchange(_variable, std::forward(value))}{ + static_assert(std::is_nothrow_assignable::value, "is is better to restrict to noexcept assignment"); + } + + ~scoped_set() { + if (_original_value) + _variable = std::move_if_noexcept(*_original_value); + } + + const_reference get() const noexcept { + return _variable; + } + + const_reference get_original_value() const { + return _original_value.value(); // may throw bad_optional_access + } + + operator const_reference() const noexcept { + return get(); + } + + void release() noexcept { + _original_value = nullopt; + } + + bool released() const noexcept { + return static_cast(_original_value); + } + +}; + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_SCOPED_SET_HPP_ */ diff --git a/include/cpp-utility/serdes.hpp b/include/cpp-utility/serdes.hpp new file mode 100644 index 0000000..da8cee4 --- /dev/null +++ b/include/cpp-utility/serdes.hpp @@ -0,0 +1,409 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file serdes.hpp +* \brief Network serialization of integers and enums. +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_SERDES_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_SERDES_HPP_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "bit.hpp" +#include "byte.hpp" +#include "to_address.hpp" +#include "type_traits.hpp" + +#if BOOST_PREDEF_WORKAROUND(BOOST_COMP_MSVC, <, 19, 32, 0) +/* + * Visual Studio fails to detect `std::contiguous_iterator` on pointers to volatile types; + * fixed on MSVC2022 17.2 (_MSC_VER == 1932). + * See https://developercommunity.visualstudio.com/t/C20-iterator-concepts-fails-on-pointer/10034979 + */ +#define CAEN_SERDES_BROKEN_STD_CONTIGUOUS_ITERATOR +#endif + +namespace caen { + +namespace serdes { + +namespace detail { + +/* + * There could be containers that provide random access iterators but not contiguous storage, + * like the infamous `std::deque` in the STL. + * + * The main difference between contiguous iterators and random access iterators is that + * the former allows, given a pointer to an value_type from an iterator, to perform pointer + * arithmetic on that pointer, which shall work in exactly the same way as performing the + * same arithmetic on the corresponding iterators. + * + * So, `std::contiguous_iterator_tag` would be correct here, but is C++20, and actually the + * `std::iterator_traits` specializations for pointers, `std::vector`, `std::array` and + * `std::string` still still return `std::random_access_iterator_tag` for backward compatibility: + * there is no way to distinguish iterator traits of `std::deque` from those of contiguous + * containers. For more details, see https://stackoverflow.com/a/42855677/3287591. + * + * Moreover, it is not easy to check if the iterator points to a contiguous container, + * before C++20, as discussed at https://stackoverflow.com/q/35004633/3287591. + * + * The problem is that this checks for `std::random_access_iterator_tag`, and does not filter + * containers like `std::deque`: in these cases it would be illegal to use reinterpret_cast + * from char* to other larger types. + * + * A correct implementation for C++20, that rejects `std::deque`, is provided. If compiling with + * pre C++20, it is up to the users of these functions to avoid containers like `std::deque`. + */ +#if __cplusplus < 202002L || defined(CAEN_SERDES_BROKEN_STD_CONTIGUOUS_ITERATOR) +inline +#endif +namespace pre_cxx20_or_broken_std_contiguous_iterator { + +template +struct is_contiguous_iterator : std::is_convertible< + typename std::iterator_traits::iterator_category, + std::random_access_iterator_tag +> {}; + +} // namespace pre_cxx20_or_broken_std_contiguous_iterator + +#if __cplusplus >= 202002L && !defined(CAEN_SERDES_BROKEN_STD_CONTIGUOUS_ITERATOR) +inline namespace cxx20_and_not_broken_std_contiguous_iterator { + +template +struct is_contiguous_iterator : std::bool_constant> {}; + +} // namespace cxx20_and_not_broken_std_contiguous_iterator +#endif + +/* + * @brief Wrapper to get iterator value_type. + * + * Since we are just looking for narrowing conversions, `std::remove_cv_t` removes qualifiers to simplify checks. + * This also to prevent issues related to LWG issue 2952. + * @sa https://cplusplus.github.io/LWG/issue2952 + * @sa https://stackoverflow.com/q/71829984/3287591 + * @tparam It iterator type + */ +template +using iterator_value_type_t = std::remove_cv_t::value_type>; + +/* + * @brief Metafunction that checks if the iterator value type is any of those provided as argument. + * + * @tparam It iterator type + * @tparam Types types to be checked against + */ +template +struct is_value_type_any_of : is_type_any_of, Types...> {}; + + +/* + * @brief Metafunction that checks if the iterator type is suitable to be used on functions in this header. + * + * Compile-time check if iterator is a contiguous iterator and if container data type is a type that supports + * reinterpret_cast to any other type(`char`, `unsigned char`, `caen::byte` without breaking the strict aliasing rule. + * An alternative approach would be to use `std::memcpy` instead of reinterpret_cast, that is the safe way to deal with + * strict aliasing rule: in our case compilers should emit the same code for `reinterpret_cast` and `std::memcpy`. + * All things considered, we prefer `std::memcpy` because it is safe also for types that have alignment requirements, + * like float on 32-bit ARM: only in these specific cases compilers should emit different code for `reinterpret_cast` + * and `std::memcpy`. + * @note `caen::pre_cxx17::byte` is added in case compiling with C++17 and still using the C++14 portable version. + * @tparam It iterator type + */ +template +struct is_valid_iterator : caen::conjunction< + is_contiguous_iterator, + is_value_type_any_of< + It, + char, + unsigned char, + caen::byte, + caen::pre_cxx17::byte + > +> {}; + +namespace sanity_checks { + +constexpr bool test_is_contiguous_iterator() noexcept { + bool ret{true}; + ret &= (is_contiguous_iterator::value); + ret &= (is_contiguous_iterator::value); + return ret; +} + +constexpr bool test_is_value_type_any_of() noexcept { + bool ret{true}; + ret &= (is_value_type_any_of::value); + ret &= (is_value_type_any_of::value); + ret &= (is_value_type_any_of::value); + ret &= (is_value_type_any_of::value); + ret &= (!is_value_type_any_of::value); + ret &= (!is_value_type_any_of::value); + ret &= (!is_value_type_any_of::value); + return ret; +} + +constexpr bool test_is_valid_iterator() noexcept { + bool ret{true}; + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (is_valid_iterator::value); + ret &= (!is_valid_iterator::value); + ret &= (!is_valid_iterator::value); + ret &= (!is_valid_iterator::value); + ret &= (!is_valid_iterator::value); + return ret; +} + +BOOST_STATIC_ASSERT(test_is_contiguous_iterator()); +BOOST_STATIC_ASSERT(test_is_value_type_any_of()); +BOOST_STATIC_ASSERT(test_is_valid_iterator()); + +} // namespace sanity_checks + +#if 107000 < BOOST_VERSION && BOOST_VERSION < 107400 +/* + * Since Boost 1.74, Boost.Endian conversion supports boolean and floating point types only with the inplace + * functions. Floating point types worked by chance also on Boost <= 1.70, but only if source and target endianness + * were equal, and booleans worked fine on the inplace function provided by <= 1.70, while its support has been + * broken on 1.71 and fixed again on 1.74. + * + * Note also that, according to C++ standard: + * - sizeof(bool) could be greater than 1 + * - floating point types could be not compliant with IEEE 754 + * + * For these reason, these types are not portable between different architectures, just like int, long, etc., and + * should be avoided when transmitting information over a network (prefer cstdint integer types, for floating + * point types you may add a static assertion on std::numeric_limits::is_iec559). + * + * For this reason, support for those types is limited and depends on the Boost version: + * - BOOST_VERSION <= 107000: + * - bool: supported + * - float/double/long double: partially supported (only with same endianness) + * - 107000 < BOOST_VERSION && BOOST_VERSION < 107400: + * - bool: not supported + * - float/double/long double: not supported + * - 107400 <= BOOST_VERSION: + * - bool: supported + * - float/double/long double: supported + */ +template +struct is_serdes_supported : caen::conjunction, caen::negation>> {}; +#else +template +struct is_serdes_supported : std::is_arithmetic {}; +#endif + +template struct boost_endian {}; // default case (compile time error) +template <> struct boost_endian { static constexpr auto order = boost::endian::order::big; }; +template <> struct boost_endian { static constexpr auto order = boost::endian::order::little; }; + +template ::value), int> = 0> +T deserialize(It& it) noexcept { + T v; + std::memcpy(&v, caen::to_address(it), sizeof(T)); + it += sizeof(T); + boost::endian::conditional_reverse_inplace(v); + return v; +} + +template ::value), int> = 0> +T deserialize(It& it) noexcept { + return static_cast(deserialize>(it)); +} + +template ::value), int> = 0> +void serialize(It& it, T v) noexcept { + boost::endian::conditional_reverse_inplace(v); + std::memcpy(caen::to_address(it), &v, sizeof(T)); + it += sizeof(T); +} + +template ::value), int> = 0> +void serialize(It& it, T v) noexcept { + serialize(it, static_cast>(v)); +} + +} // namespace detail + +/** + * @brief Decode a value of a given type from a raw buffer, increasing the input iterator. + * + * @tparam Endian the source endianness + * @tparam TOut the output type (must be trivially copyable) + * @tparam It a pointer or an iterator type to a raw buffer (value type must be char, unsigned char or caen::byte) + * @param it the iterator that will be increased by sizeof(T) + * @return the value + */ +template +TOut deserialize_endian(It& it) noexcept { + static_assert(std::is_trivially_copyable::value, "output type must be trivially copyable"); + static_assert(detail::is_valid_iterator::value, "invalid iterator value type"); + return detail::deserialize::order, TOut, It>(it); +} + +/** + * @brief Convenience function for template argument deduction. + * + * @overload + */ +template +void deserialize_endian(It& it, TOut& res) noexcept { + res = deserialize_endian(it); +} + +/** + * @brief Encode a value of a given type into a raw buffer, increasing the input iterator. + * + * @tparam Endian the target endianness (big is the default for network) + * @tparam TIn the input type (must be trivially copyable) + * @tparam It a pointer or an iterator type to a raw buffer (value type must be char, unsigned char or caen::byte) + * @param it the iterator that will be increased by sizeof(T) + * @param v the value + */ +template +void serialize_endian(It& it, TIn v) noexcept { + static_assert(std::is_trivially_copyable::value, "input type must be trivially copyable"); + static_assert(detail::is_valid_iterator::value, "invalid iterator value type"); + detail::serialize::order, TIn, It>(it, v); +} + +/** + * @brief Decode a value of a given type from a big-endian raw buffer, increasing the input iterator. + * + * @tparam TOut the output type (must be trivially copyable) + * @tparam It a pointer or an iterator type to a raw buffer (value type must be char, unsigned char or caen::byte) + * @param it the iterator that will be increased by sizeof(T) + * @return the value + */ +template +TOut deserialize(It& it) noexcept { + return deserialize_endian(it); +} + +/** + * @brief Convenience function for template argument deduction. + * + * @overload + */ +template +void deserialize(It& it, TOut& res) noexcept { + res = deserialize(it); +} + +/** + * @brief Encode a value of a given type into a big-endian raw buffer, increasing the input iterator. + * + * @tparam TIn the input type (must be trivially copyable) + * @tparam It a pointer or an iterator type to a raw buffer (value type must be char, unsigned char or caen::byte) + * @param it the iterator that will be increased by sizeof(T) + * @param v the value + */ +template +void serialize(It& it, TIn v) noexcept { + serialize_endian(it, v); +} + +/** + * @brief Decode a value of a given type from a little-endian raw buffer, increasing the input iterator. + * + * @tparam TOut the output type (must be trivially copyable) + * @tparam It a pointer or an iterator type to a raw buffer (value type must be char, unsigned char or caen::byte) + * @param it the iterator that will be increased by sizeof(T) + * @return the value + */ +template +TOut deserialize_little(It& it) noexcept { + return deserialize_endian(it); +} + +/** + * @brief Convenience function for template argument deduction. + * + * @overload + */ +template +void deserialize_little(It& it, TOut& res) noexcept { + res = deserialize_little(it); +} + +/** + * @brief Encode a value of a given type into a little-endian raw buffer, increasing the input iterator. + * + * @tparam TIn the input type (must be trivially copyable) + * @tparam It a pointer or an iterator type to a raw buffer (value type must be char, unsigned char or caen::byte) + * @param it the iterator that will be increased by sizeof(T) + * @param v the value + */ +template +void serialize_little(It& it, TIn v) noexcept { + serialize_endian(it, v); +} + +} // namespace serdes + +// import also into caen namespace +using serdes::deserialize_endian; +using serdes::serialize_endian; +using serdes::deserialize; +using serdes::serialize; +using serdes::deserialize_little; +using serdes::serialize_little; + +} // namespace caen + +#undef CAEN_SERDES_BROKEN_STD_CONTIGUOUS_ITERATOR + +#endif /* CAEN_INCLUDE_CPP_UTILITY_SERDES_HPP_ */ diff --git a/include/cpp-utility/socket_option.hpp b/include/cpp-utility/socket_option.hpp new file mode 100644 index 0000000..ad473fe --- /dev/null +++ b/include/cpp-utility/socket_option.hpp @@ -0,0 +1,67 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file socket_option.hpp +* \brief Platform independent extension to Boost.ASIO socket options +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_SOCKET_OPTION_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_SOCKET_OPTION_HPP_ + +#include +#include + +#if BOOST_OS_WINDOWS +#include +#elif BOOST_OS_MACOS || BOOST_OS_LINUX +#include +#else +#error unsupported operating system +#endif + +namespace caen { + +namespace socket_option { + +using keep_interval = boost::asio::detail::socket_option::integer; +using keep_cnt = boost::asio::detail::socket_option::integer; +#if BOOST_OS_MACOS +using keep_idle = boost::asio::detail::socket_option::integer; +#else +using keep_idle = boost::asio::detail::socket_option::integer; +#endif + +} // namespace socket_option + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_SOCKET_OPTION_HPP_ */ diff --git a/include/cpp-utility/span.hpp b/include/cpp-utility/span.hpp new file mode 100644 index 0000000..8352fdd --- /dev/null +++ b/include/cpp-utility/span.hpp @@ -0,0 +1,425 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2019 Glen Joseph Fernandes (glenjofe@gmail.com) +* +* This file is distributed under the Boost Software License, Version 1.0. +* (http://www.boost.org/LICENSE_1_0.txt) +* +* SPDX-License-Identifier: BSL-1.0 +* +***************************************************************************//*! +* +* \file span.hpp +* \brief `std::span` replacement, copied from single header implementation in Boost 1.78.0. +* \author Glen Joseph Fernandes, Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_SPAN_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_SPAN_HPP_ + +#include +#include +#include +#include + +#include "byte.hpp" + +/* + * We could use `std::span` when compiling as C++20 but, unfortunately, it + * is not supported by Boost.Range: we prefer to always use `boost::span` + * because Boost.Range is largely used across CAEN libraries. + * + * Alternatives to replace Boost.Range could be: + * - standard *Ranges library*, available since C++20 too + * - *range-v3*, essentially the same of the standard Ranges library, + * compatible with C++14 but that would restrict supported compilers + * to GCC >= 6.5, clang >= 5.0 (no problems with VS2019) + * + * The second option would be preferable, also because preparatory to a + * smooth migration to C++20. Anyway, we prefer to keep this + * implementation, at least until we'll be able to drop GCC 5 support. + * See https://github.com/boostorg/range/issues/142. + * + * We also do not provide fallback to `boost::span` with inline namespace + * based on BOOST_VERSION >= 107800 because `boost::span::as_bytes` and + * `boost::span::as_writable_bytes` are available only on C++17, while + * here they are always available because based on `caen::byte`. + */ + +namespace caen { + +constexpr std::size_t dynamic_extent = static_cast(-1); + +template +class span; + +namespace detail { + +template +struct span_convertible { + static constexpr bool value = std::is_convertible::value; +}; + +template +struct span_capacity { + static constexpr bool value = E == dynamic_extent || E == N; +}; + +template +struct span_compatible { + static constexpr bool value = span_capacity::value && + span_convertible::value; +}; + +template +struct span_uncvref { + typedef typename std::remove_cv::type>::type type; +}; + +template +struct span_is_span { + static constexpr bool value = false; +}; + +template +struct span_is_span> { + static constexpr bool value = true; +}; + +template +struct span_is_array { + static constexpr bool value = false; +}; + +template +struct span_is_array > { + static constexpr bool value = true; +}; + +template +struct span_data { }; + +template +struct span_data().data())>::value>::type> { + typedef typename std::remove_pointer().data())>::type type; +}; + +template +struct span_has_data { + static constexpr bool value = false; +}; + +template +struct span_has_data::type, T>::value>::type> { + static constexpr bool value = true; +}; + +template +struct span_has_size { + static constexpr bool value = false; +}; + +template +struct span_has_size().size()), + std::size_t>::value>::type> { + static constexpr bool value = true; +}; + +template +struct span_is_range { + static constexpr bool value = (std::is_const::value || + std::is_lvalue_reference::value) && + !span_is_span::type>::value && + !span_is_array::type>::value && + !std::is_array::type>::value && + span_has_data::value && + span_has_size::value; +}; + +template +struct span_implicit { + static constexpr bool value = E == dynamic_extent || + N != dynamic_extent; +}; + +template +struct span_copyable { + static constexpr bool value = (N == dynamic_extent || + span_capacity::value) && span_convertible::value; +}; + +template +struct span_sub { + static constexpr std::size_t value = E == dynamic_extent ? + dynamic_extent : E - O; +}; + +template +struct span_store { + constexpr span_store(T* p_, std::size_t) noexcept + : p(p_) { } + static constexpr std::size_t n = E; + T* p; +}; + +template +struct span_store { + constexpr span_store(T* p_, std::size_t n_) noexcept + : p(p_) + , n(n_) { } + T* p; + std::size_t n; +}; + +template +struct span_bytes { + static constexpr std::size_t value = sizeof(T) * E; +}; + +template +struct span_bytes { + static constexpr std::size_t value = dynamic_extent; +}; + +} /* detail */ + +template +class span { +public: + typedef T element_type; + typedef typename std::remove_cv::type value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T* iterator; + typedef const T* const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + static constexpr std::size_t extent = E; + + template::type = 0> + constexpr span() noexcept + : s_(0, 0) { } + + template::value, int>::type = 0> + constexpr span(I* f, size_type c) + : s_(f, c) { } + + template::value, int>::type = 0> + explicit constexpr span(I* f, size_type c) + : s_(f, c) { } + + template::value, int>::type = 0> + constexpr span(I* f, L* l) + : s_(f, l - f) { } + + template::value, int>::type = 0> + explicit constexpr span(I* f, L* l) + : s_(f, l - f) { } + + template::value, + int>::type = 0> + constexpr span(typename std::enable_if::type (&a)[N]) noexcept + : s_(a, N) { } + + template::value, + int>::type = 0> + constexpr span(std::array& a) noexcept + : s_(a.data(), N) { } + + template::value, int>::type = 0> + constexpr span(const std::array& a) noexcept + : s_(a.data(), N) { } + + template::value, int>::type = 0> + constexpr span(R&& r) noexcept(noexcept(r.data()) && noexcept(r.size())) + : s_(r.data(), r.size()) { } + + template::value, int>::type = 0> + explicit constexpr span(R&& r) noexcept(noexcept(r.data()) && + noexcept(r.size())) + : s_(r.data(), r.size()) { } + + template::value && + detail::span_copyable::value, int>::type = 0> + constexpr span(const span& s) noexcept + : s_(s.data(), s.size()) { } + + template::value && + detail::span_copyable::value, int>::type = 0> + explicit constexpr span(const span& s) noexcept + : s_(s.data(), s.size()) { } + + template + constexpr span first() const { + static_assert(C <= E, "Count <= Extent"); + return span(s_.p, C); + } + + template + constexpr span last() const { + static_assert(C <= E, "Count <= Extent"); + return span(s_.p + (s_.n - C), C); + } + + template + constexpr typename std::enable_if::value> >::type subspan() const { + static_assert(O <= E, "Offset <= Extent"); + return span::value>(s_.p + O, s_.n - O); + } + + template + constexpr typename std::enable_if >::type subspan() const { + static_assert(O <= E && C <= E - O, + "Offset <= Extent && Count <= Extent - Offset"); + return span(s_.p + O, C); + } + + constexpr span first(size_type c) const { + return span(s_.p, c); + } + + constexpr span last(size_type c) const { + return span(s_.p + (s_.n - c), c); + } + + constexpr span subspan(size_type o, + size_type c = dynamic_extent) const { + return span(s_.p + o, + c == dynamic_extent ? s_.n - o : c); + } + + constexpr size_type size() const noexcept { + return s_.n; + } + + constexpr size_type size_bytes() const noexcept { + return s_.n * sizeof(T); + } + + constexpr bool empty() const noexcept { + return s_.n == 0; + } + + constexpr reference operator[](size_type i) const { + return s_.p[i]; + } + + constexpr reference front() const { + return *s_.p; + } + + constexpr reference back() const { + return s_.p[s_.n - 1]; + } + + constexpr pointer data() const noexcept { + return s_.p; + } + + constexpr iterator begin() const noexcept { + return s_.p; + } + + constexpr iterator end() const noexcept { + return s_.p + s_.n; + } + + constexpr reverse_iterator rbegin() const noexcept { + return reverse_iterator(s_.p + s_.n); + } + + constexpr reverse_iterator rend() const noexcept { + return reverse_iterator(s_.p); + } + + constexpr const_iterator cbegin() const noexcept { + return s_.p; + } + + constexpr const_iterator cend() const noexcept { + return s_.p + s_.n; + } + + constexpr const_reverse_iterator crbegin() const noexcept { + return const_reverse_iterator(s_.p + s_.n); + } + + constexpr const_reverse_iterator crend() const noexcept { + return const_reverse_iterator(s_.p); + } + + friend constexpr iterator begin(span s) noexcept { + return s.begin(); + } + + friend constexpr iterator end(span s) noexcept { + return s.end(); + } + +private: + detail::span_store s_; +}; + +template +constexpr std::size_t span::extent; + +template +inline span::value> +as_bytes(span s) noexcept +{ + return span::value>(reinterpret_cast(s.data()), + s.size_bytes()); +} + +template +inline typename std::enable_if::value, + span::value> >::type +as_writable_bytes(span s) noexcept +{ + return span::value>(reinterpret_cast(s.data()), s.size_bytes()); +} + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_SPAN_HPP_ */ \ No newline at end of file diff --git a/include/cpp-utility/string.hpp b/include/cpp-utility/string.hpp new file mode 100644 index 0000000..86ecd11 --- /dev/null +++ b/include/cpp-utility/string.hpp @@ -0,0 +1,409 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file string.hpp +* \brief String utilities +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_STRING_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_STRING_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "counting_range.hpp" +#include "math.hpp" +#include "type_traits.hpp" + +namespace caen { + +namespace string { + +namespace detail { + +template +struct has_size : std::false_type {}; + +template +struct has_size().size())>> : std::true_type {}; + +template +struct all_have_size : conjunction...> {}; + +template::value, int> = 0> +bool iequals(const Range1T& input, const Range2T& test) { + return (test.size() == input.size()) && boost::iequals(input, test); +} + +template::value, int> = 0> +bool iequals(const Range1T& input, const Range2T& test) { + return boost::iequals(input, test); +} + +template ::value, int> = 0> +T string_to_number_impl(const String& str, std::size_t& sz) { + const auto temp_result = std::stoul(str, &sz, Base); + if (std::numeric_limits::max() < temp_result) + throw std::out_of_range("stob/stouc/stous/stou"); + return static_cast(temp_result); +} +template ::value, int> = 0> +T string_to_number_impl(const String& str, std::size_t& sz) { + return std::stoul(str, &sz, Base); +} +template ::value, int> = 0> +T string_to_number_impl(const String& str, std::size_t& sz) { + return std::stoull(str, &sz, Base); +} +template ::value, int> = 0> +T string_to_number_impl(const String& str, std::size_t& sz) { + const auto temp_result = std::stoi(str, &sz, Base); + if (temp_result < std::numeric_limits::lowest() || std::numeric_limits::max() < temp_result) + throw std::out_of_range("stosc/stos"); + return static_cast(temp_result); +} +template ::value, int> = 0> +T string_to_number_impl(const String& str, std::size_t& sz) { + return std::stoi(str, &sz, Base); +} +template ::value, int> = 0> +T string_to_number_impl(const String& str, std::size_t& sz) { + return std::stol(str, &sz, Base); +} +template ::value, int> = 0> +T string_to_number_impl(const String& str, std::size_t& sz) { + return std::stoll(str, &sz, Base); +} +template ::value, int> = 0> +T string_to_number_impl(const String& str, std::size_t& sz) { + static_assert(Base == 0, "Base template argument is unused, kept for consistency in the template signature. Must be zero."); + return std::stof(str, &sz); +} +template ::value, int> = 0> +T string_to_number_impl(const String& str, std::size_t& sz) { + static_assert(Base == 0, "Base template argument is unused, kept for consistency in the template signature. Must be zero."); + return std::stod(str, &sz); +} +template ::value, int> = 0> +T string_to_number_impl(const String& str, std::size_t& sz) { + static_assert(Base == 0, "Base template argument is unused, kept for consistency in the template signature. Must be zero."); + return std::stold(str, &sz); +} + +template +T string_to_number(const String& str) { + std::size_t sz; + const T result = string_to_number_impl(str, sz); + if (sz < str.size()) + throw std::invalid_argument("string_to_number: unexpected characters"); + return result; +} + +template ::value, int> = 0> +T float_to_number(Float value) { + return caen::math::round(value); +} +template ::value, int> = 0> +T float_to_number(Float value) { + if (value < std::numeric_limits::lowest() || std::numeric_limits::max() < value) + throw std::out_of_range("value cannot be represented"); + return static_cast(value); +} + +template +T string_to_number_safe(const String& str) { + static_assert(std::is_floating_point::value, "intermediate type must be floating point number"); + // first convert to floating point, then convert it to desired type + return float_to_number(string_to_number(str)); +} + +template ::value, int> = 0> +bool is_space(Char c) { + // unsigned char cast needed, provided by to_int_type (https://en.cppreference.com/w/cpp/string/byte/isspace) + return std::isspace(std::char_traits::to_int_type(c)); +} +template ::value, int> = 0> +bool is_space(Char c) { + // see comment on char version + return std::iswspace(std::char_traits::to_int_type(c)); +} +template ::value, int> = 0> +bool is_space(Char c) { + // generic version, slower since depends on std::locale + return std::isspace(c, std::locale{}); +} + +template ::value, int> = 0> +bool is_printable(Char c) { + // see commend on is_space + return std::isprint(std::char_traits::to_int_type(c)) != 0; +} + +template ::value, int> = 0> +bool is_printable(Char c) { + // see commend on is_space + return std::iswprint(std::char_traits::to_int_type(c)) != 0; +} + +template ::value, int> = 0> +bool is_printable(Char c) { + // see commend on is_space + return std::isprint(c, std::locale()); +} + +template +struct null_terminator : std::integral_constant::to_char_type(0)> {}; + +template +String pointer_to_string_safe(const Char* ptr, typename String::size_type max_len) { + BOOST_ASSERT_MSG(!is_printable(null_terminator::value), "invalid implementation"); + if (ptr == nullptr) + return String{}; + const auto range = caen::counting_range(max_len); + const auto it = std::find_if_not(range.begin(), range.end(), [ptr](auto i) { return is_printable(ptr[i]); }); + if (it == range.end() || ptr[*it] != null_terminator::value) + return String{}; + return String(ptr, *it); +} + +template +void string_to_pointer_safe(Char* dst, const String& src, typename String::size_type max_size) { + if (dst == nullptr) + return; + if (src.size() >= max_size) + throw std::runtime_error("string too long to be copied"); + const auto n = src.copy(dst, max_size - 1); + dst[n] = null_terminator::value; +} + +namespace sanity_checks { + +constexpr bool test_null_terminator() noexcept { + bool ret{true}; + ret &= (null_terminator::value == *""); + ret &= (null_terminator::value == *L""); + ret &= (null_terminator::value == *u""); + ret &= (null_terminator::value == *U""); + return ret; +} + +BOOST_STATIC_ASSERT(test_null_terminator()); + +} // namespace sanity_checks + +} // namespace detail + +/** + * @brief Same of `boost::iequals`, with possible performance improvement based on string sizes. + * + * `boost::iequals` only compares strings by iterating character by character, + * but if input types have `size()` method with complexity O(1) this could + * provide a faster check without any dereferences. We could use the generic + * `boost::size`/`std::size` to extend this approach also when input is a char + * array, but it returns the size of the array including the null terminator. + * We could subtract 1 to this value, but seems to become too elaborated. + * Using `std::char_traits::length` would require iterating the array, + * and then vanishing any advantage of this approach. So, the approach of + * `size()` is used only if both input types provides a `size()` method, + * assuming that it has complexity O(1). + * @tparam Range1T input string type + * @tparam Range2T test string type + * @param[in] input input string + * @param[in] test test string + * @return true if strings are equal (case insensitive) + */ +template +bool iequals(const Range1T& input, const Range2T& test) { + return detail::iequals(input, test); +} + +/** + * @brief Convert string to any arithmetic type, with intermediate conversion to double. + * + * We cannot use directly `std::sto*` functions when using strings generated + * by converting `double` to string, that could also have exponential + * representation. So, we first convert string to `double`, then trying + * to cast intermediate `double` to desired type. + * @tparam T output numeric type + * @tparam String input string type + * @param[in] value input string + * @return the result of conversion + */ +template +T to_number_safe(const String& value) { + static_assert(std::is_arithmetic::value, "output type must be arithmetic"); + return detail::string_to_number_safe(value); +} + +/** + * @brief Convenience function for template argument deduction. + * + * @overload + */ +template +void to_number_safe(T& v, const String& value) { + v = to_number_safe(value); +} + +/** + * @brief Convert string to any arithmetic type. + * + * Safe wrapper to the `std::sto*` functions. Similar also to the functions + * provided by `caen::conversion::lexical_cast()`. Except for the underlying + * implementation, the main difference is that this can also be used to parse + * values with base auto-detection (like "0x", "0X" or "0"), not supported by + * the `caen::conversion::lexical_cast()`. + * @warning The behavior of this function depends on the current C locale (that could be different from the global C++ locale). + * @tparam T output numeric type + * @tparam Base base argument passed to `std::sto*` functions. + * @tparam String input string type + * @param[in] value input string + * @return the result of conversion + */ +template +T to_number(const String& value) { + static_assert(std::is_arithmetic::value, "output type must be arithmetic"); + return detail::string_to_number(value); +} + +/** + * @brief Convenience function for template argument deduction. + * + * Template argument order is changed to allow base specification with + * the deduction of the other template arguments. + * @overload + */ +template +void to_number(T& v, const String& value) { + v = to_number(value); +} + +/** + * @brief Remove space characters from string + * + * @tparam String input string type + * @param[in] value input string + * @return a string with any space character removed + */ +template +decltype(auto) remove_spaces(String&& value) { + auto res = std::forward(value); // copy + auto it = std::remove_if(res.begin(), res.end(), [](auto c) { return detail::is_space(c); }); + res.erase(it, res.end()); + return res; +} + +/** + * @brief Remove space characters from string + * + * @tparam String input string type + * @tparam Range range type + * @tparam Vector output type + * @param[in] value input string + * @param[in] range a set of characters to be recognized as delimiters + * @return split input string as a container + */ +template >> +decltype(auto) split_string(String&& value, Range&& range) { + Vector ret; + boost::split(ret, std::forward(value), boost::is_any_of(std::forward(range))); + return ret; +} + +/** + * @brief Convenience overload with "|" as delimiter. + * + * @overload + */ +template +decltype(auto) split_string(String&& value) { + return split_string(std::forward(value), "|"); +} + +/** + * @brief Inverse of split_string overload for "|" as delimiter. + * + * @tparam Container container type + * @param[in] value input container + * @return a concatenated string + */ +template +decltype(auto) join_string(Container&& value) { + return boost::join(std::forward(value), "|"); +} + +template > +String pointer_to_string_safe(const Char* src, typename String::size_type max_size) { + BOOST_STATIC_ASSERT(std::is_same::value); + return detail::pointer_to_string_safe(src, max_size); +} + +template +void string_to_pointer_safe(Char* dst, const String& src, typename String::size_type max_size) { + BOOST_STATIC_ASSERT(std::is_same::value); + detail::string_to_pointer_safe(dst, src, max_size); +} + +/** + * @brief Split a string like "0x10=24" in (0x10, 24) + * + * @tparam String string type + * @tparam NumberLeft left number type + * @tparam NumberRight right number type + * @param[in] value input string + * @param[out] lh left number + * @param[out] rh right number + */ +template +void parse_values_with_equal(String&& value, NumberLeft& lh, NumberRight& rh) { + const auto v = split_string(std::forward(value), "="); + if (v.size() != 2) + throw std::invalid_argument(value); + to_number(lh, v[0]); + to_number(rh, v[1]); +} + +} // namespace string + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_STRING_HPP_ */ diff --git a/include/cpp-utility/string_to_pointer.hpp b/include/cpp-utility/string_to_pointer.hpp new file mode 100644 index 0000000..af49efc --- /dev/null +++ b/include/cpp-utility/string_to_pointer.hpp @@ -0,0 +1,50 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file string_to_pointer.hpp +* \brief Legacy include, to be replaced with string.hpp +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_STRING_TO_POINTER_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_STRING_TO_POINTER_HPP_ + +#include "string.hpp" + +namespace caen { + +// import also into caen namespace +using string::string_to_pointer_safe; +using string::pointer_to_string_safe; + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_STRING_TO_POINTER_HPP_ */ diff --git a/include/cpp-utility/string_view.hpp b/include/cpp-utility/string_view.hpp new file mode 100644 index 0000000..7941cab --- /dev/null +++ b/include/cpp-utility/string_view.hpp @@ -0,0 +1,108 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file string_view.hpp +* \brief `std::string_view` replacement +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_STRING_VIEW_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_STRING_VIEW_HPP_ + +#if __cplusplus >= 201703L +#include +#endif + +#include +#include + +namespace caen { + +#if __cplusplus < 201703L +inline +#endif +namespace pre_cxx17 { + +using boost::basic_string_view; //!< Use boost::basic_string_view on pre C++17. + +} // namespace pre_cxx17 + +#if __cplusplus >= 201703L +inline namespace cxx17 { + +using std::basic_string_view; //!< Use std::basic_string_view on C++17 and after. + +} // namespace cxx17 +#endif + +/** +* @defgroup StringViewDefines String view definitions +* @brief Definitions of drop-in replacement for `std::string_view` (and relative types for wider strings). +* +* Drop-in replacements to be used instead of `std::string_view` when building +* with standard pre C++17. +* +* @{ */ +using string_view = basic_string_view; +using wstring_view = basic_string_view; +using u16string_view = basic_string_view; +using u32string_view = basic_string_view; +/** @} */ + +inline namespace literals { + +/** +* @defgroup StringViewLiterals String view literals +* @brief Definitions of UDL `operator""_sv`. +* +* Drop-in replacements to be used instead of standard UDL `operator""sv` +* when building with standard pre C++17. +* +* @{ */ +constexpr auto operator""_sv(const char* str, std::size_t len) noexcept { + return basic_string_view{str, len}; +} +constexpr auto operator""_sv(const wchar_t* str, std::size_t len) noexcept { + return basic_string_view{str, len}; +} +constexpr auto operator""_sv(const char16_t* str, std::size_t len) noexcept { + return basic_string_view{str, len}; +} +constexpr auto operator""_sv(const char32_t* str, std::size_t len) noexcept { + return basic_string_view{str, len}; +} +/** @} */ + +} // namespace literals + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_STRING_VIEW_HPP_ */ diff --git a/include/cpp-utility/ticket_mutex.hpp b/include/cpp-utility/ticket_mutex.hpp new file mode 100644 index 0000000..eb4278b --- /dev/null +++ b/include/cpp-utility/ticket_mutex.hpp @@ -0,0 +1,147 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file ticket_mutex.hpp +* \brief Ticket mutex that meets C++ Mutex requirements +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_TICKET_MUTEX_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_TICKET_MUTEX_HPP_ + +#include +#include +#include +#include + +namespace caen { + +namespace detail { + +#if __cplusplus < 201703L +inline +#endif +namespace pre_cxx17 { + +// to emulate returning emplace also on C++14 +template +decltype(auto) emplace(std::queue& q, Args&& ...args) { + return q.emplace(std::forward(args)...), q.back(); +} + +} // namespace pre_cxx17 + +#if __cplusplus >= 201703L +inline namespace cxx17 { + +template +decltype(auto) emplace(std::queue& q, Args&& ...args) { + return q.emplace(std::forward(args)...); +} + +} // namespace cxx17 +#endif + + +struct extended_condition_variable { + extended_condition_variable() : _var{false} {} + bool _var; + std::condition_variable _cv; +}; + +} // namespace detail + +/** + * @brief Fair mutex that meets C++ Mutex requirements. + * + * Can be used with `std::lock_guard` and `std::unique_lock` while, since + * `std::condition_variable` supports only `std::mutex`, it must be used + * with `std::condition_variable_any`. + * @sa https://en.cppreference.com/w/cpp/named_req/Mutex + */ +struct ticket_mutex { + + ticket_mutex() : _locked{false} {}; + + /** + * @brief Blocks the calling thread until exclusive ownership can be obtained. + * + * @warning The behavior is undefined if the calling thread already owns it. + */ + void lock() { + std::unique_lock lk{_mtx}; + if (std::exchange(_locked, true)) { + auto& ecv = detail::emplace(_queue); + ecv._cv.wait(lk, [&ecv] { return ecv._var; }); + _queue.pop(); + } + } + + /** + * @brief Attempts to obtain exclusive ownership. + * + * @warning The function is allowed to spuriously fail and return even if the not currently owned by another thread. + * @return true if lock succeeded, false if already locked + */ + bool try_lock() { + std::unique_lock lk{_mtx, std::try_to_lock}; + // owns_lock may fail if another thread is locking internal _mtx + if (!lk.owns_lock() || _locked) + return false; + _locked = true; + return true; + } + + /** + * @brief Releases the calling thread's ownership. + * + * @warning The behavior is undefined if the calling thread does not own it. + */ + void unlock() { + std::unique_lock lk{_mtx}; + if (_queue.empty()) { + _locked = false; + } else { + auto& ecv = _queue.front(); + ecv._var = true; + ecv._cv.notify_one(); + } + } + +private: + std::queue _queue; + std::mutex _mtx; + bool _locked; +}; + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_TICKET_MUTEX_HPP_ */ diff --git a/include/cpp-utility/to_address.hpp b/include/cpp-utility/to_address.hpp new file mode 100644 index 0000000..c1c6845 --- /dev/null +++ b/include/cpp-utility/to_address.hpp @@ -0,0 +1,83 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file to_address.hpp +* \brief `std::to_address` basic replacement +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_TO_ADDRESS_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_TO_ADDRESS_HPP_ + +#include + +namespace caen { + +/** + * @brief Replacement of `std::to_address` for raw pointers. + * + * @tparam T any type, except function + * @param p raw pointer + * @return p unmodified + */ +template +constexpr T* to_address(T* p) noexcept { + static_assert(!std::is_function::value, "function type not supported"); + return p; +} + +/** + * @brief Basic replacement of `std::to_address` for fancy pointers. + * + * This class works like `std::to_address`, except that the support for + * overloaded `std::pointer_traits::to_address` for fancy pointers is + * deliberately missing. + * + * We could use Boost.Core `boost::to_address` on pre C++20, identical but + * relying pointer traits on `boost` namespace insted of those on `std`. + * Moreover, the support for `std::array` iterator is broken on <= Boost 1.79 + * when compiling with Visual Studio 2019. + * + * In light of all this, we provide a basic support just to convert iterators + * to the underlying address. + * + * @tparam Ptr fancy pointer type (e.g. an iterator type) + * @param p fancy pointer + * @return the value, static-casted to its underlying type + */ +template +constexpr auto to_address(const Ptr& p) noexcept { + return caen::to_address(p.operator->()); +} + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_TO_ADDRESS_HPP_ */ diff --git a/include/cpp-utility/to_underlying.hpp b/include/cpp-utility/to_underlying.hpp new file mode 100644 index 0000000..bd25413 --- /dev/null +++ b/include/cpp-utility/to_underlying.hpp @@ -0,0 +1,82 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file to_underlying.hpp +* \brief `std::to_underlying` replacement +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_TO_UNDERLYING_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_TO_UNDERLYING_HPP_ + +#include + +#if defined(__has_include) && __has_include() +#include // C++20 +#endif + +#ifdef __cpp_lib_to_underlying +#include +#endif + +namespace caen { + +#ifndef __cpp_lib_to_underlying +inline +#endif +namespace no_std_to_underlying { + +/** + * @brief Replacement for `std::to_underlying`. + * + * @tparam Enum enumerator type + * @param value enumerator value + * @return the value, static-casted to its underlying type + */ +template +constexpr auto to_underlying(Enum value) noexcept { + using underlying_type = std::underlying_type_t; + return static_cast(value); +} + +} // namespace no_std_to_underlying + +#ifdef __cpp_lib_to_underlying +inline namespace std_to_underlying { + +using std::to_underlying; + +} // namespace std_to_underlying +#endif + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_TO_UNDERLYING_HPP_ */ diff --git a/include/cpp-utility/type_traits.hpp b/include/cpp-utility/type_traits.hpp new file mode 100644 index 0000000..00d0e63 --- /dev/null +++ b/include/cpp-utility/type_traits.hpp @@ -0,0 +1,174 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file type_traits.hpp +* \brief replacement for some C++17 traits +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_TYPE_TRAITS_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_TYPE_TRAITS_HPP_ + +#include +#include + +#if defined(__has_include) && __has_include() +#include // C++20 +#endif + +#include +#include + +namespace caen { + +#if __cplusplus < 201703L +inline +#endif +namespace pre_cxx17 { + +using boost::void_t; + +template +struct bool_constant : std::integral_constant {}; + +template +struct disjunction : std::false_type {}; +template +struct disjunction : std::conditional_t> {}; + +template +struct conjunction : std::true_type {}; +template +struct conjunction : std::conditional_t, std::false_type> {}; + +template +struct negation : bool_constant {}; + +// `boost::callable_traits::is_invocable` not working with function with empty arguments list +// Implementation from https://stackoverflow.com/a/51188325/3287591 +template +struct is_invocable : + std::is_constructible< + std::function, + std::reference_wrapper::type> + > {}; + +template +struct is_invocable_r : + std::is_constructible< + std::function, + std::reference_wrapper::type> + > {}; + +namespace sanity_checks { + +constexpr bool test_type_traits() noexcept { + bool ret{true}; + ret &= (std::is_void>::value); + ret &= (bool_constant::value); + ret &= (!bool_constant::value); + ret &= (conjunction::value); + ret &= (!conjunction::value); + ret &= (disjunction::value); + ret &= (!disjunction::value); + ret &= (negation::value); + ret &= (!negation::value); + ret &= (is_invocable::value); + ret &= (!is_invocable::value); + ret &= (is_invocable_r::value); + ret &= (!is_invocable_r::value); + return ret; +} + +BOOST_STATIC_ASSERT(test_type_traits()); + +} // namespace sanity_checks + +} // namespace pre_cxx17 + +#if __cplusplus >= 201703L +inline namespace cxx17 { + +using std::void_t; +using std::bool_constant; +using std::conjunction; +using std::disjunction; +using std::negation; +using std::is_invocable; +using std::is_invocable_r; + +} // namespace cxx17 +#endif + +#ifndef __cpp_lib_remove_cvref +inline +#endif +namespace no_std_remove_cvref { + +template +struct remove_cvref { + typedef std::remove_cv_t> type; +}; + +template +using remove_cvref_t = typename remove_cvref::type; + +} // namespace no_std_remove_cvref + +#ifdef __cpp_lib_remove_cvref +inline namespace std_remove_cvref { + +using std::remove_cvref; +using std::remove_cvref_t; + +} // namespace std_remove_cvref +#endif + +template +struct is_type_any_of : disjunction, Types>...> {}; + +namespace sanity_checks { + +constexpr bool test_is_type_any_of() noexcept { + bool ret{true}; + ret &= is_type_any_of::value; + ret &= !is_type_any_of::value; + ret &= !is_type_any_of::value; + return ret; +} + +BOOST_STATIC_ASSERT(test_is_type_any_of()); + +} // namespace sanity_checks + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_TYPE_TRAITS_HPP_ */ diff --git a/include/cpp-utility/value_with_digits.hpp b/include/cpp-utility/value_with_digits.hpp new file mode 100644 index 0000000..a3c0687 --- /dev/null +++ b/include/cpp-utility/value_with_digits.hpp @@ -0,0 +1,74 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file value_with_digits.hpp +* \brief Floating point value with number of digits +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_VALUE_WITH_DIGITS_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_VALUE_WITH_DIGITS_HPP_ + +#include + +#include + +#include + +namespace caen { + +template +struct value_with_digits { + + BOOST_STATIC_ASSERT(std::is_floating_point::value); + + constexpr value_with_digits(T value, unsigned int ndigits) noexcept + : _value{value} + , _ndigits{ndigits} {} + + constexpr auto get_value() const noexcept { return _value; } + constexpr auto get_ndigits() const noexcept { return _ndigits; } + + std::string to_string() const { + return fmt::format("{:.{}f}", _value, _ndigits); + } + +private: + T _value; + unsigned int _ndigits; +}; + +using double_with_digits = value_with_digits; +using float_with_digits = value_with_digits; + +} // namespace caen + +#endif /* CAEN_INCLUDE_CPP_UTILITY_VALUE_WITH_DIGITS_HPP_ */ diff --git a/include/cpp-utility/variant.hpp b/include/cpp-utility/variant.hpp new file mode 100644 index 0000000..777b991 --- /dev/null +++ b/include/cpp-utility/variant.hpp @@ -0,0 +1,296 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file variant.hpp +* \brief `std::variant` replacement +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_VARIANT_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_VARIANT_HPP_ + +#include + +#if __cplusplus >= 201703L +#include +#endif + +#include +#include +#include + +#if BOOST_PREDEF_WORKAROUND(BOOST_COMP_CLANG, <=, 7, 0, 0) +/** + * @brief Workaround for Clang bug 33222. + * + * Workaround for clang compilation error for std::variant using GCC's 7.1 libstdc++: + * if needed, use the pre-C++17 fallback. + * This also requires to rename pre_cxx17 namespace to something else, because + * somewhere else pre_cxx17 could be inline. + * @sa https://bugs.llvm.org/show_bug.cgi?id=33222 + */ +#define CAEN_VARIANT_WORKAROUND_CLANG_BUG_33222 +#endif + +#if BOOST_PREDEF_WORKAROUND(BOOST_COMP_CLANG, >=, 16, 0, 0) +/** + * @brief Workaround for Boost.MPL issue 69. + * + * Exclude **Boost.Variant** from clang 16 because of a bug in **Boost.MPL**, + * apparently already workarounded in Boost.Variant 1.81. + * This patch can be removed when changing minimum Boost version to at least + * 1.71.0, dropping **Boost.Variant**. + * This workaround removes the legacy fallback if Boost < 1.81 and compiling + * with -std=c++14 (that would be weird on clang 16). + * @sa https://github.com/boostorg/mpl/issues/69 + */ +#define CAEN_VARIANT_WORKAROUND_CLANG_16 +#if __cplusplus < 201703L && BOOST_VERSION < 108100 +#error On clang > 16 you need either C++17 or Boost >= 1.81.0 +#endif +#endif + +#ifndef CAEN_VARIANT_WORKAROUND_CLANG_16 +#include +#endif + +/* + * **Boost.Variant2** is provided since Boost 1.71. Unlike **Boost.Variant**, + * its interface is compatible with `std::variant`, except, like **Boost.Variant**, + * it provides the "never-empty" guarantee. + */ +#if BOOST_VERSION >= 107100 +#include +#define CAEN_VARIANT_USE_BOOST_VARIANT2 +#endif + +namespace caen { + +#ifndef CAEN_VARIANT_WORKAROUND_CLANG_16 // don't compile if not available + +#if (__cplusplus < 201703L || defined(CAEN_VARIANT_WORKAROUND_CLANG_BUG_33222)) && !defined(CAEN_VARIANT_USE_BOOST_VARIANT2) +inline +#endif +namespace pre_cxx17_or_clang_7_boost_variant { + +/** + * @brief Replacement for `std::variant` using **Boost.Variant**. + * + * The main differences are: + * - `boost::variant` allocated on heap + * - `boost::variant` provides the "never-empty" guarantee + * - `boost::variant` has no constexpr support + * - some methods are missing (e.g. `std::holds_alternative` and `std::variant::valueless_by_exception`) + * - have a different name (e.g. `std::visit`, `std::get_if` and `std::variant::index`) + * + * We try to implement the missing stuff, except for `std::get` and emplace() overloads that + * takes numeric index as template argument instead of a type. + */ +template +class variant : private boost::variant { +public: + +#if BOOST_PREDEF_WORKAROUND(BOOST_COMP_CLANG, <, 3, 9, 0) + /// Base constructor is fine (workaround for a known bug in clang < 3.9) + template + variant(Args&&... args) noexcept(std::is_nothrow_constructible, Args...>::value) + : boost::variant::variant(std::forward(args)...) { + } +#else + /// Base constructor is fine. + using boost::variant::variant; +#endif + + /// `boost::variant::operator=` are fine. + using boost::variant::operator=; + + /// `boost::variant::swap` is fine but we cannot simply use "using" because of different argument type. + void swap(variant& rhs) { + boost::variant::swap(rhs); + } + + /// `boost::variant::which` is the same of `std::variant::index` except for the return type. + std::size_t index() const noexcept { + return static_cast(this->which()); + } + + /// `boost::variant` provides the "never-empty" guarantee, cannot be valueless. + constexpr bool valueless_by_exception() const noexcept { + return false; + } + + /// `boost::variant::emplace` is missing and not easy to be implemented; this does almost the same thing. + template + decltype(auto) emplace(Args&&... args) { + *this = TIn(std::forward(args)...); + return boost::get(*this); + } + + /// Not standard but required by `boost::apply_visitor`. + using typename boost::variant::types; + + /// Not standard but required by `boost::apply_visitor`. + using boost::variant::apply_visitor; + + /// Trick to reuse `boost::get` using private inheritance. Should not be used directly. + template + decltype(auto) _impl_get() const & { + return boost::get(*this); + } + + /// Trick to reuse `boost::get` using private inheritance. Should not be used directly. + template + decltype(auto) _impl_get() & { + return boost::get(*this); + } + + /// Trick to reuse `boost::get` using private inheritance. Should not be used directly. + template + decltype(auto) _impl_get() && { + return boost::get(std::move(*this)); + } + + /// Trick to reuse `boost::get` using private inheritance. Should not be used directly. + template + decltype(auto) _impl_get_if() noexcept { + return boost::get(this); + } + + /// Trick to reuse `boost::get` using private inheritance. Should not be used directly. + template + decltype(auto) _impl_get_if() const noexcept { + return boost::get(this); + } + +}; + +/** + * @brief Replacement for `std::monostate`, an empty struct used as placeholder. + */ +struct monostate {}; + +/** + * @brief `boost::apply_visitor` is almost identical to `std::visit`, except for the different name. + */ +template +decltype(auto) visit(Args&& ...args) { + return boost::apply_visitor(std::forward(args)...); +} + +/** + * @brief `boost::get` is just fine to replace `std::get`. + * + * We use a workaround to avoid public inheritance from `boost::variant`: being a class without + * virtual destructor, it is not a good idea to inherit from it. + */ +template +decltype(auto) get(Variant&& v) { + return std::forward(v).template _impl_get(); +} + +/** + * @brief `boost::get` overloads with pointers as argument are renamed `std::get_if` in the standard implementation. + * + * In the standard implementation, overloads of `boost::get` with pointers as argument are not overloads + * but are renamed `std::get_if`. + * We use a workaround to avoid public inheritance from `boost::variant`: being a class without + * virtual destructor, it is not a good idea to inherit from it. + */ +template +decltype(auto) get_if(VariantPtr* vptr) noexcept { + return vptr != nullptr ? vptr->template _impl_get_if() : nullptr; +} + +/** + * @brief `boost::variant` has nothing like `std::holds_alternative`, but it can be implemented in terms of get_if(). + */ +template +bool holds_alternative(const variant& v) noexcept { + return (get_if(&v) != nullptr); +} + +template +struct variant_size; +template +struct variant_size : variant_size::type {}; +template +struct variant_size : variant_size::type {}; +template +struct variant_size : variant_size::type {}; + +/** + * @brief `boost::variant` has nothing like `std::variant_size`, but it can be implemented easily. + */ +template +struct variant_size> : std::integral_constant {}; + +} // namespace pre_cxx17_or_clang_7_boost_variant + +#endif + +#ifdef CAEN_VARIANT_USE_BOOST_VARIANT2 // don't compile if not available +#if (__cplusplus < 201703L || defined(CAEN_VARIANT_WORKAROUND_CLANG_BUG_33222)) +inline +#endif +namespace pre_cxx17_or_clang_7_boost_variant2 { + +using boost::variant2::variant; +using boost::variant2::monostate; +using boost::variant2::get; +using boost::variant2::get_if; +using boost::variant2::visit; +using boost::variant2::holds_alternative; +using boost::variant2::variant_size; + +} // namespace pre_cxx17_or_clang_7_boost_variant2 +#endif + +#if __cplusplus >= 201703L && !defined(CAEN_VARIANT_WORKAROUND_CLANG_BUG_33222) +inline namespace cxx17 { + +using std::variant; +using std::monostate; +using std::get; +using std::get_if; +using std::visit; +using std::holds_alternative; +using std::variant_size; + +} // namespace cxx17 +#endif + +} // namespace caen + +#undef CAEN_VARIANT_USE_BOOST_VARIANT2 +#undef CAEN_VARIANT_WORKAROUND_CLANG_16 +#undef CAEN_VARIANT_WORKAROUND_CLANG_BUG_33222 + +#endif /* CAEN_INCLUDE_CPP_UTILITY_VARIANT_HPP_ */ diff --git a/include/cpp-utility/vector.hpp b/include/cpp-utility/vector.hpp new file mode 100644 index 0000000..db6d9c7 --- /dev/null +++ b/include/cpp-utility/vector.hpp @@ -0,0 +1,244 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file vector.hpp +* \brief `std::vector` with default initialization allocator +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_VECTOR_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_VECTOR_HPP_ + +#include +#include +#include + +#include +#include +#include + +#if BOOST_VERSION >= 107100 +#include +#define CAEN_USE_BOOST_NOINIT_ADAPTOR +#endif + +#include + +namespace caen { + +#ifndef CAEN_USE_BOOST_NOINIT_ADAPTOR +inline +#endif +namespace caen_noinit_adaptor { + +/** + * @brief Custom allocator to reduce resize complexity of `std::vector` of POD data. + * + * Allocator adaptor that interposes construct() calls to convert value initialization + * into default initialization. Used by default @ref caen::vector. + * @tparam Allocator The allocator (e.g. `std::allocator`) + * @sa https://stackoverflow.com/a/21028912/3287591 + */ +template +struct noinit_adaptor : public Allocator { + +private: + using allocator_traits = std::allocator_traits; + +public: + template + struct rebind { + using other = noinit_adaptor>; + }; + + using Allocator::Allocator; + + /** + * @brief Perform default initialization. + * + * If no argument is provided, use this convenience overload to perform + * default initialization (note `U` without braces): it is a no-op on POD + * and the default constructor in case of class type. + * @sa https://en.cppreference.com/w/cpp/language/default_initialization + * @sa https://en.cppreference.com/w/cpp/memory/allocator/construct + * @note This is the core of this class. + * @note Implemented just like `std::allocator::construct` without braces. + */ + template + void construct(U* ptr) noexcept(std::is_nothrow_default_constructible::value) { + ::new (const_cast(static_cast(ptr))) U; + } + +}; + +} // namespace caen_noinit_adaptor + +#ifdef CAEN_USE_BOOST_NOINIT_ADAPTOR +inline namespace boost_noinit_adaptor { + +using boost::noinit_adaptor; + +} // namespace boost_noinit_adaptor +#endif + +/** + * @brief Same of `std::vector`, with an allocator designed to improve performance on POD types. + * + * If the type of elements is a POD, then `resize` is much faster + * since is done with default constructor instead of value initialization used by + * `std::allocator` (i.e. memory is not filled to zero on vector::resize()). + * @tparam T the type of the elements + * @tparam Allocator the allocator, set to @ref caen::noinit_adaptor by default + */ +template >> +using vector = std::vector; + +/** + * @brief Clear and release memory allocated by a vector. + * + * `vector::clear()` does not modify vector capacity unless we call + * `vector::shrink_to_fit()`, that however is not required to release + * memory. This approach, instead, actually releases the memory. + * Just for completeness, until C++11 the copy assignment did not + * release memory, and a `vector::swap()` approach was required. + * @tparam T type of the elements + * @tparam Allocator allocator + * @param v vector + */ +template +void reset(vector& v) noexcept { + v = vector(); +} + +/** + * @brief Clear vector and set new capacity, releasing unnecessary memory. + * + * Since `std::allocator` uses `new`/`delete`, that are never implemented with + * `realloc`, every reallocation is performed with `malloc`/`memcpy`/`free`. + * So, in case we need a different capacity, either bigger or smaller, + * we just recreate a new vector, to be sure to optimize memory usage. + * @tparam Vector type of the vector + * @param v vector + * @param new_capacity new capacity + */ +template +void reserve(vector& v, typename vector::size_type new_capacity) { + if (new_capacity != v.capacity()) { + reset(v); + v.reserve(new_capacity); + } else { + v.clear(); + } +} + +/** + * @brief Clear vector. + * + * @tparam T type of the elements + * @tparam Allocator allocator + * @param v vector + */ +template +void clear(vector& v) noexcept { + v.clear(); +} + +/** + * @brief Resize vector with debug log message if requires reallocation. + * + * @tparam T type of the elements + * @tparam Allocator allocator + * @param v vector + * @param new_size new size + */ +template +void resize(vector& v, typename vector::size_type new_size) { + if (BOOST_UNLIKELY(v.capacity() < new_size)) + SPDLOG_DEBUG("need to reallocate memory (current capacity: {}, needed: {})", v.capacity(), new_size); + v.resize(new_size); +} + +/** + * @brief Set all values to `typename vector::value_type{}`. + * + * @tparam T type of the elements + * @tparam Allocator allocator + * @param v vector + */ +template +void set_default(vector& v) noexcept { + boost::fill(v, typename vector::value_type{}); +} + +#if __cplusplus < 201703L +inline +#endif +namespace pre_cxx17 { + +/** + * @brief Wrapper to port returning behavior of `emplace_back` on C++14. + * + * @tparam T type of the elements + * @tparam Allocator allocator + * @param v vector + * @param args emplace_back arguments + */ +template +decltype(auto) emplace_back(vector& v, Args&& ...args) { + return v.emplace_back(std::forward(args)...), v.back(); +} + +} // namespace pre_cxx17 + +#if __cplusplus >= 201703L +inline namespace cxx17 { + +/** + * @brief Wrapper to port returning behavior of `emplace_back` on C++14. + * + * @tparam T the type of the elements + * @tparam Allocator the allocator + * @param v the vector + * @param args emplace_back arguments + */ +template +decltype(auto) emplace_back(vector& v, Args&& ...args) { + return v.emplace_back(std::forward(args)...); +} + +} // namespace cxx17 +#endif + +} // namespace caen + +#undef CAEN_USE_BOOST_NOINIT_ADAPTOR + +#endif /* CAEN_INCLUDE_CPP_UTILITY_VECTOR_HPP_ */ \ No newline at end of file diff --git a/include/cpp-utility/win32_process_terminate.hpp b/include/cpp-utility/win32_process_terminate.hpp new file mode 100644 index 0000000..d5d11d8 --- /dev/null +++ b/include/cpp-utility/win32_process_terminate.hpp @@ -0,0 +1,123 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN C++ Utility. +* +* The CAEN C++ Utility is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN C++ Utility is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN C++ Utility; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file win32_process_terminate.hpp +* \brief Utility class to handle proper shutdown on Windows +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_CPP_UTILITY_WIN32_PROCESS_TERMINATE_HANDLER_HPP_ +#define CAEN_INCLUDE_CPP_UTILITY_WIN32_PROCESS_TERMINATE_HANDLER_HPP_ + +#include + +#if BOOST_OS_WINDOWS + +#include +#include +#include + +#if __cplusplus >= 202002L +#include +#endif + +#include +#include + +namespace caen { + +namespace win32_process_terminate { + +struct handler : private boost::noncopyable { + + // singleton + static handler& get_instance() { + static handler instance; + return instance; + } + + void set_process_terminating() noexcept { + _is_process_terminating = true; + } + + bool is_process_terminating() const noexcept { + return _is_process_terminating; + } + +private: + + handler() : _is_process_terminating{false} {}; + ~handler() = default; + + bool _is_process_terminating; +}; + +inline bool is_thread_signaled_if_joinable(std::thread& t) { + return !t.joinable() || boost::winapi::WaitForSingleObject(t.native_handle(), 0) == boost::winapi::wait_object_0; +} + +inline bool is_thread_not_signaled_if_joinable(std::thread& t) { + return !t.joinable() || boost::winapi::WaitForSingleObject(t.native_handle(), 0) == boost::winapi::wait_timeout; +} + +#if __cplusplus < 202002L +inline +#endif +namespace pre_cxx20 { + +/** + * @brief Replacement for `std::construct_at` on pre C++20. + * + * @note Cannot be done `constexpr` because it requires compiler support. + * @sa https://en.cppreference.com/w/cpp/memory/construct_at + */ +template +T* construct_at(T* p, Args&& ...args) { + return ::new (const_cast(static_cast(p))) T(std::forward(args)...); +} + +} // namespace pre_cxx20 + +#if __cplusplus >= 202002L +inline namespace cxx20 { + +using std::construct_at; + +} // namespace cxx20 +#endif + +} // namespace win32_process_terminate + +} // namespace caen + +#endif + +#endif /* CAEN_INCLUDE_CPP_UTILITY_WIN32_PROCESS_TERMINATE_HANDLER_HPP_ */ diff --git a/include/data_format_utils.hpp b/include/data_format_utils.hpp new file mode 100644 index 0000000..c53a159 --- /dev/null +++ b/include/data_format_utils.hpp @@ -0,0 +1,125 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file data_format_utils.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_DATA_FORMAT_UTILS_HPP_ +#define CAEN_INCLUDE_DATA_FORMAT_UTILS_HPP_ + +#include +#include +#include +#include + +#include +#include +#include + +#include "cpp-utility/type_traits.hpp" +#include "json/json_data_format.hpp" +#include "endpoints/endpoint.hpp" +#include "lib_error.hpp" + +namespace caen { + +namespace dig2 { + +namespace ep { + +namespace detail { + +template +struct is_default_data_format_defined + : std::false_type {}; + +template +struct is_default_data_format_defined> + : caen::is_invocable_r {}; + +template +struct is_data_format_dimension_defined + : std::false_type {}; + +template +struct is_data_format_dimension_defined> + : caen::is_invocable_r::names_type> {}; + +} // namespace detail + +/* + * Utility struct to reuse the logic of the endpoint::set_data_format implementation in each endpoint. + * Being "names" type different in each endpoint, it cannot implement it in base class. + */ +template +struct data_format_utils { + + using traits = utility::endpoint_traits; + using args_list_t = typename traits::args_list_type; + using args_type = typename args_list_t::value_type; + + static_assert(detail::is_data_format_dimension_defined::value, "endpoint must define data_format_dimension function"); + static_assert(detail::is_default_data_format_defined::value, "endpoint must define a default_data_format function returning a type convertible to args_list_t"); + + template + static void parse_data_format(args_list_t& list, String&& json_format) { + if (json_format.empty()) { + list = Endpoint::default_data_format(); + } else { + const auto j = nlohmann::json::parse(std::forward(json_format)); + args_list_t new_list; + new_list.reserve(j.size()); + boost::transform(j, std::back_inserter(new_list), [](const nlohmann::json& element) { + const auto format = element.get>(); // json to object + if (traits::is_unknown(format.get_name())) + throw ex::invalid_argument(fmt::format("invalid name in {}", element.dump())); + if (traits::is_unknown(format.get_type())) + throw ex::invalid_argument(fmt::format("invalid type in {}", element.dump())); + const auto expected_dim = Endpoint::data_format_dimension(format.get_name()); + if (expected_dim != format.get_dim()) + throw ex::invalid_argument(fmt::format("invalid dim in {} (must be {})", element.dump(), expected_dim)); + return args_type{format.get_name(), format.get_type(), format.get_dim()}; + }); + list = std::move(new_list); + } + } + +}; + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_DATA_FORMAT_UTILS_HPP_ */ diff --git a/include/discovery.hpp b/include/discovery.hpp new file mode 100644 index 0000000..b9efdad --- /dev/null +++ b/include/discovery.hpp @@ -0,0 +1,59 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file discovery.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_DISCOVERY_HPP_ +#define CAEN_INCLUDE_DISCOVERY_HPP_ + +#include + +#include + +namespace caen { + +namespace dig2 { + +namespace ssdp { + +nlohmann::json get_ssdp_devices(std::chrono::milliseconds timeout_ms); + +} // namespace ssdp + +} // namespace dig2 + +} // namespace caen + + +#endif /* CAEN_INCLUDE_DISCOVERY_HPP_ */ diff --git a/include/endpoints/aggregate_endpoint.hpp b/include/endpoints/aggregate_endpoint.hpp new file mode 100644 index 0000000..33747d5 --- /dev/null +++ b/include/endpoints/aggregate_endpoint.hpp @@ -0,0 +1,105 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file aggregate_endpoint.hpp +* \brief Aggregate event base endpoint +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_AGGREGATE_ENDPOINT_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_AGGREGATE_ENDPOINT_HPP_ + +#include + +#include "cpp-utility/integer.hpp" +#include "endpoints/sw_endpoint.hpp" + +namespace caen { + +namespace dig2 { + +namespace ep { + +struct aggregate_endpoint : public sw_endpoint { + + aggregate_endpoint(client& client, handle::internal_handle_t endpoint_handle); + ~aggregate_endpoint(); + +protected: + struct dpp_aggregate_header { + struct s { + static constexpr std::size_t format{evt_header::s::format}; + static constexpr std::size_t flush{1}; + static constexpr std::size_t tbd_1{2}; + static constexpr std::size_t board_fail{1}; + static constexpr std::size_t aggregate_counter{24}; + static constexpr std::size_t n_words{evt_header::s::n_words}; + static_assert(flush + tbd_1 + board_fail + aggregate_counter == evt_header::s::implementation_defined, "invalid sizes"); + }; + // constants + static constexpr std::size_t aggregate_header_words{1}; + static constexpr std::size_t aggregate_header_size{aggregate_header_words * word_size}; + // fields + evt_header::format _format; + bool _flush; + // - tbd_1 not saved into event + bool _board_fail; + caen::uint_t::fast _aggregate_counter; + caen::uint_t::fast _n_words; + }; + + bool decode_aggregate_header(const caen::byte*& p) noexcept; + const dpp_aggregate_header& last_aggregate_header() const noexcept; + + /* + * Utility functions to handle clear in aggregate endpoints: if a clear() is sent while + * the decode() is in the middle of a loop of an aggregate, we require an asynchronous + * flag to interrupt the decode and discard remaining events of the current aggregate. + */ + + // shall be called by clear_data() + void require_clear() noexcept; + + // shall be invoked by decode() before beginning a new hit + bool is_clear_required_and_reset() noexcept; + +private: + struct aggregate_endpoint_impl; // forward declaration + std::unique_ptr _pimpl; +}; + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_AGGREGATE_ENDPOINT_HPP_ */ diff --git a/include/endpoints/dpp_probe_types.hpp b/include/endpoints/dpp_probe_types.hpp new file mode 100644 index 0000000..7ced3b5 --- /dev/null +++ b/include/endpoints/dpp_probe_types.hpp @@ -0,0 +1,95 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file dpp_probe_types.hpp +* \brief Enumerators for common DPP probe type codes +* \author Bruno Angelucci, Giovanni Cerretani, Alberto Potenza +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_DPP_PROBE_TYPES_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_DPP_PROBE_TYPES_HPP_ + +#include + +namespace caen { + +namespace dig2 { + +namespace ep { + +enum struct dpp_digital_probe_type : std::uint8_t { + unknown = 0xff, + // common (PHA firmware values) + trigger = 0b00000, + time_filter_armed = 0b00001, + re_trigger_guard = 0b00010, + energy_filter_baseline_freeze = 0b00011, + event_pile_up = 0b00111, + // PHA specific (PHA firmware values) + energy_filter_peaking = 0b00100, + energy_filter_peak_ready = 0b00101, + energy_filter_pile_up_guard = 0b00110, + adc_saturation = 0b01000, + adc_saturation_protection = 0b01001, + post_saturation_event = 0b01010, + energy_filter_saturation = 0b01011, + signal_inhibit = 0b01100, + // PSD specific (PSD firmware values with offset 0b10000) + over_threshold = 0b10100, + charge_ready = 0b10101, + long_gate = 0b10110, + short_gate = 0b11000, + input_saturation = 0b11001, + charge_over_range = 0b11010, + negative_over_threshold = 0b11011, +}; + +enum struct dpp_analog_probe_type : std::uint8_t { + unknown = 0xff, + // common (PHA firmware values) + adc_input = 0b0000, + // PHA specific (PHA firmware values) + time_filter = 0b0001, + energy_filter = 0b0010, + energy_filter_baseline = 0b0011, + energy_filter_minus_baseline = 0b0100, + // PSD specific (PSD firmware values with offset 0b1000) + baseline = 0b1001, + cfd = 0b1010, +}; + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_DPP_PROBE_TYPES_HPP_ */ diff --git a/include/endpoints/dpppha.hpp b/include/endpoints/dpppha.hpp new file mode 100644 index 0000000..10af461 --- /dev/null +++ b/include/endpoints/dpppha.hpp @@ -0,0 +1,386 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file dpppha.hpp +* \brief Decoded endpoint for DPP-PHA +* \author Giovanni Cerretani, Alberto Potenza +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_DPPPHA_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_DPPPHA_HPP_ + +#include +#include +#include +#include +#include + +#include + +#include "cpp-utility/integer.hpp" +#include "cpp-utility/optional.hpp" +#include "cpp-utility/vector.hpp" +#include "endpoints/aggregate_endpoint.hpp" +#include "endpoints/dpp_probe_types.hpp" + +namespace caen { + +namespace dig2 { + +namespace ep { + +struct dpppha final : public aggregate_endpoint { + + enum class names { // overrides endpoint::names + UNKNOWN, + CHANNEL, + TIMESTAMP, + TIMESTAMP_NS, + FINE_TIMESTAMP, + ENERGY, + FLAGS_LOW_PRIORITY, + FLAGS_HIGH_PRIORITY, + TRIGGER_THR, + TIME_RESOLUTION, + ANALOG_PROBE_1, + ANALOG_PROBE_1_TYPE, + ANALOG_PROBE_2, + ANALOG_PROBE_2_TYPE, + DIGITAL_PROBE_1, + DIGITAL_PROBE_1_TYPE, + DIGITAL_PROBE_2, + DIGITAL_PROBE_2_TYPE, + DIGITAL_PROBE_3, + DIGITAL_PROBE_3_TYPE, + DIGITAL_PROBE_4, + DIGITAL_PROBE_4_TYPE, + WAVEFORM_SIZE, + BOARD_FAIL, + AGGREGATE_COUNTER, + FLUSH, + EVENT_SIZE, + }; + + using args_list_t = utility::args_list_t; + + dpppha(client& client, handle::internal_handle_t endpoint_handle); + ~dpppha(); + + void resize() override; + void decode(const caen::byte* p, std::size_t size) override; + void stop() override; + void set_data_format(const std::string &json_format) override; + void read_data(timeout_t timeout, std::va_list* args) override; + void has_data(timeout_t timeout) override; + void clear_data() override; + + static args_list_t default_data_format(); + static std::size_t data_format_dimension(names name); + + struct stats final : public endpoint { + + enum class names { // overrides endpoint::names + UNKNOWN, + REAL_TIME, + REAL_TIME_NS, + DEAD_TIME, + DEAD_TIME_NS, + LIVE_TIME, + LIVE_TIME_NS, + TRIGGER_CNT, + SAVED_EVENT_CNT, + }; + + using args_list_t = utility::args_list_t; + struct time_info { + using type = std::uint64_t; + type _dead_time; + }; + struct counter_info { + using type = std::uint32_t; + type _trigger_cnt; + type _saved_event_cnt; + }; + + stats(client& client, handle::internal_handle_t endpoint_handle); + ~stats(); + + void set_data_format(const std::string& json_format) override; + void read_data(timeout_t timeout, std::va_list* args) override; + void has_data(timeout_t timeout) override; + void clear_data() override; + + void update(std::size_t channel, time_info::type timestamp, caen::optional time_info, caen::optional counter_info); + + static args_list_t default_data_format(); + static std::size_t data_format_dimension(names name); + + private: + + struct endpoint_impl; // forward declaration + std::unique_ptr _pimpl; + + }; + +private: + struct hit_evt { + struct s { + // 1st word + static constexpr std::size_t last_word{1}; // first bit of each word + static constexpr std::size_t channel{7}; + static constexpr std::size_t special_event{1}; + static constexpr std::size_t tbd_1{7}; + static constexpr std::size_t timestamp{48}; + static constexpr std::size_t timestamp_reduced{32}; + // 2nd word + static constexpr std::size_t has_waveform{1}; + static constexpr std::size_t flag_low_priority{12}; + static constexpr std::size_t flag_high_priority{8}; + static constexpr std::size_t tbd_2{16}; + static constexpr std::size_t fine_timestamp{10}; + static constexpr std::size_t energy{16}; + // 3rd word + static constexpr std::size_t extra_type{3}; + static constexpr std::size_t extra_data{60}; + }; + enum struct extra_type : caen::uint_t::fast { + wave_info = 0b000, + time_info = 0b001, + counter_info = 0b010, + }; + struct wave_info_data { + struct digital_probe { + struct s { + // part of 3rd word (extra) + static constexpr std::size_t type{4}; + // part of waveform word + static constexpr std::size_t sample{1}; + }; + enum struct type : caen::uint_t::fast { + trigger = 0b0000, + time_filter_armed = 0b0001, + re_trigger_guard = 0b0010, + energy_filter_baseline_freeze = 0b0011, + energy_filter_peaking = 0b0100, + energy_filter_peak_ready = 0b0101, + energy_filter_pile_up_guard = 0b0110, + event_pile_up = 0b0111, + adc_saturation = 0b1000, + adc_saturation_protection = 0b1001, + post_saturation_event = 0b1010, + energy_filter_saturation = 0b1011, + signal_inhibit = 0b1100, + }; + // fields + type _type; + dpp_digital_probe_type _decoded_type; // decoded common type + caen::vector::least> _data; + }; + struct analog_probe { + struct s { + // part of 3rd word (extra) + static constexpr std::size_t mul_factor{2}; + static constexpr std::size_t is_signed{1}; + static constexpr std::size_t type{3}; + // part of waveform word + static constexpr std::size_t sample{14}; + static constexpr std::size_t decoded_sample{sample + 4}; // 4 is factor_16 + }; + enum struct mul_factor : caen::uint_t::fast { + factor_1 = 0b00, + factor_4 = 0b01, + factor_8 = 0b10, + factor_16 = 0b11, + }; + enum struct type : caen::uint_t::fast { + adc_input = 0b000, + time_filter = 0b001, + energy_filter = 0b010, + energy_filter_baseline = 0b011, + energy_filter_minus_baseline = 0b100, + }; + // fields + mul_factor _mul_factor; + bool _is_signed; + type _type; + dpp_analog_probe_type _decoded_type; // decoded common type + caen::vector::least> _data; + caen::vector::least> _decoded_data; + decltype(_decoded_data)::value_type _decoded_mul_factor; + }; + struct s { + // 3rd word (extra), other fields described in analog_probe::s and digital_probe::s + static constexpr std::size_t tbd_1{14}; + static constexpr std::size_t time_resolution{2}; + static constexpr std::size_t trigger_thr{16}; + // waveform size word + static constexpr std::size_t truncated{1}; + static constexpr std::size_t tbd_2{51}; + static constexpr std::size_t waveform_n_words{12}; + // waveform word + static constexpr std::size_t n_digital_probes{4}; + static constexpr std::size_t n_analog_probes{2}; + static constexpr std::size_t sample{n_analog_probes * analog_probe::s::sample + n_digital_probes * digital_probe::s::sample}; + }; + enum struct time_resolution : caen::uint_t::fast { + no_downsampling = 0b00, + downsampling_x2 = 0b01, + downsampling_x4 = 0b10, + downsampling_x8 = 0b11, + }; + // constants + static constexpr extra_type extra_id{extra_type::wave_info}; + static constexpr std::size_t samples_per_word{word_bit_size / s::sample}; + static constexpr std::size_t max_waveform_words{4095}; + static constexpr std::size_t max_waveform_samples{max_waveform_words * samples_per_word}; + // fields + // - tbd_1 not saved into event + time_resolution _time_resolution; + caen::uint_t::fast _trigger_thr; + std::array _digital_probes; + std::array _analog_probes; + // - truncated not saved into event + // - tbd_2 not saved into event + // - waveform_n_words not saved into event + }; + struct time_info_data { + struct s { + static constexpr std::size_t tbd_1{12}; + static constexpr std::size_t dead_time{48}; + }; + // constants + static constexpr extra_type extra_id{extra_type::time_info}; + // fields + // - tbd_1 not saved into event + caen::uint_t::fast _dead_time; + }; + struct counter_info_data { + struct s { + static constexpr std::size_t tbd_1{12}; + static constexpr std::size_t trigger_cnt{24}; + static constexpr std::size_t saved_event_cnt{24}; + }; + // constants + static constexpr extra_type extra_id{extra_type::counter_info}; + // fields + // - tbd_1 not saved into event + caen::uint_t::fast _trigger_cnt; + caen::uint_t::fast _saved_event_cnt; + }; + // fields + caen::uint_t::fast _channel; + // - special_event not saved into event + // - tbd_1 not saved into event + caen::uint_t::fast _timestamp; + // - has_waveform not saved into event + caen::uint_t::fast _flag_low_priority; + caen::uint_t::fast _flag_high_priority; + // - tbd_2 not saved into event + caen::uint_t::fast _fine_timestamp; + caen::uint_t::fast _energy; + // - extra_type not saved into event + // - extra_data not saved into event + wave_info_data _wave_info_data; + std::size_t _event_size; + // fields from aggregate header + bool _board_fail; + bool _flush; + caen::uint_t::fast _aggregate_counter; + // software fields + bool _fake_stop_event; + // consistency assertions + static_assert(std::is_same::value, "documented to be handled as std::uint8_t"); + static_assert(std::is_same::value, "documented to be handled as std::uint16_t"); + static_assert(std::is_same::value, "documented to be handled as std::int32_t"); + }; + + // decode internal implementation + void decode_hit(const caen::byte*& p); + void decode_hit_waveform(const caen::byte*& p, hit_evt::wave_info_data& ed); + + struct endpoint_impl; // forward declaration + std::unique_ptr _pimpl; + + std::shared_ptr _stats_ep; + +}; + +using namespace std::string_literals; + +NLOHMANN_JSON_SERIALIZE_ENUM(dpppha::names, { + { dpppha::names::UNKNOWN, nullptr }, + { dpppha::names::CHANNEL, "CHANNEL"s }, + { dpppha::names::TIMESTAMP, "TIMESTAMP"s }, + { dpppha::names::TIMESTAMP_NS, "TIMESTAMP_NS"s }, + { dpppha::names::FINE_TIMESTAMP, "FINE_TIMESTAMP"s }, + { dpppha::names::ENERGY, "ENERGY"s }, + { dpppha::names::FLAGS_LOW_PRIORITY, "FLAGS_LOW_PRIORITY"s }, + { dpppha::names::FLAGS_HIGH_PRIORITY, "FLAGS_HIGH_PRIORITY"s }, + { dpppha::names::TRIGGER_THR, "TRIGGER_THR"s }, + { dpppha::names::TIME_RESOLUTION, "TIME_RESOLUTION"s }, + { dpppha::names::ANALOG_PROBE_1, "ANALOG_PROBE_1"s }, + { dpppha::names::ANALOG_PROBE_1_TYPE, "ANALOG_PROBE_1_TYPE"s }, + { dpppha::names::ANALOG_PROBE_2, "ANALOG_PROBE_2"s }, + { dpppha::names::ANALOG_PROBE_2_TYPE, "ANALOG_PROBE_2_TYPE"s }, + { dpppha::names::DIGITAL_PROBE_1, "DIGITAL_PROBE_1"s }, + { dpppha::names::DIGITAL_PROBE_1_TYPE, "DIGITAL_PROBE_1_TYPE"s }, + { dpppha::names::DIGITAL_PROBE_2, "DIGITAL_PROBE_2"s }, + { dpppha::names::DIGITAL_PROBE_2_TYPE, "DIGITAL_PROBE_2_TYPE"s }, + { dpppha::names::DIGITAL_PROBE_3, "DIGITAL_PROBE_3"s }, + { dpppha::names::DIGITAL_PROBE_3_TYPE, "DIGITAL_PROBE_3_TYPE"s }, + { dpppha::names::DIGITAL_PROBE_4, "DIGITAL_PROBE_4"s }, + { dpppha::names::DIGITAL_PROBE_4_TYPE, "DIGITAL_PROBE_4_TYPE"s }, + { dpppha::names::WAVEFORM_SIZE, "WAVEFORM_SIZE"s }, + { dpppha::names::BOARD_FAIL, "BOARD_FAIL"s }, + { dpppha::names::AGGREGATE_COUNTER, "AGGREGATE_COUNTER"s }, + { dpppha::names::FLUSH, "FLUSH"s }, + { dpppha::names::EVENT_SIZE, "EVENT_SIZE"s }, +}) + +NLOHMANN_JSON_SERIALIZE_ENUM(dpppha::stats::names, { + { dpppha::stats::names::UNKNOWN, nullptr }, + { dpppha::stats::names::REAL_TIME, "REAL_TIME"s }, + { dpppha::stats::names::REAL_TIME_NS, "REAL_TIME_NS"s }, + { dpppha::stats::names::DEAD_TIME, "DEAD_TIME"s }, + { dpppha::stats::names::DEAD_TIME_NS, "DEAD_TIME_NS"s }, + { dpppha::stats::names::LIVE_TIME, "LIVE_TIME"s }, + { dpppha::stats::names::LIVE_TIME_NS, "LIVE_TIME_NS"s }, + { dpppha::stats::names::TRIGGER_CNT, "TRIGGER_CNT"s }, + { dpppha::stats::names::SAVED_EVENT_CNT, "SAVED_EVENT_CNT"s }, +}) + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_DPPPHA_HPP_ */ diff --git a/include/endpoints/dpppsd.hpp b/include/endpoints/dpppsd.hpp new file mode 100644 index 0000000..6b97668 --- /dev/null +++ b/include/endpoints/dpppsd.hpp @@ -0,0 +1,386 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file dpppsd.hpp +* \brief Decoded endpoint for DPP-PSD +* \author Giovanni Cerretani, Alberto Potenza +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_DPPPSD_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_DPPPSD_HPP_ + +#include +#include +#include +#include +#include + +#include + +#include "cpp-utility/integer.hpp" +#include "cpp-utility/optional.hpp" +#include "cpp-utility/vector.hpp" +#include "endpoints/aggregate_endpoint.hpp" +#include "endpoints/dpp_probe_types.hpp" + +namespace caen { + +namespace dig2 { + +namespace ep { + +struct dpppsd final : public aggregate_endpoint { + + enum class names { // overrides endpoint::names + UNKNOWN, + CHANNEL, + TIMESTAMP, + TIMESTAMP_NS, + FINE_TIMESTAMP, + ENERGY, + ENERGY_SHORT, + FLAGS_LOW_PRIORITY, + FLAGS_HIGH_PRIORITY, + TRIGGER_THR, + TIME_RESOLUTION, + ANALOG_PROBE_1, + ANALOG_PROBE_1_TYPE, + ANALOG_PROBE_2, + ANALOG_PROBE_2_TYPE, + DIGITAL_PROBE_1, + DIGITAL_PROBE_1_TYPE, + DIGITAL_PROBE_2, + DIGITAL_PROBE_2_TYPE, + DIGITAL_PROBE_3, + DIGITAL_PROBE_3_TYPE, + DIGITAL_PROBE_4, + DIGITAL_PROBE_4_TYPE, + WAVEFORM_SIZE, + BOARD_FAIL, + AGGREGATE_COUNTER, + FLUSH, + EVENT_SIZE, + }; + + using args_list_t = utility::args_list_t; + + dpppsd(client& client, handle::internal_handle_t endpoint_handle); + ~dpppsd(); + + void resize() override; + void decode(const caen::byte* p, std::size_t size) override; + void stop() override; + void set_data_format(const std::string &json_format) override; + void read_data(timeout_t timeout, std::va_list* args) override; + void has_data(timeout_t timeout) override; + void clear_data() override; + + static args_list_t default_data_format(); + static std::size_t data_format_dimension(names name); + + struct stats final : public endpoint { + + enum class names { // overrides endpoint::names + UNKNOWN, + REAL_TIME, + REAL_TIME_NS, + DEAD_TIME, + DEAD_TIME_NS, + LIVE_TIME, + LIVE_TIME_NS, + TRIGGER_CNT, + SAVED_EVENT_CNT, + }; + + using args_list_t = utility::args_list_t; + struct time_info { + using type = std::uint64_t; + type _dead_time; + }; + struct counter_info { + using type = std::uint32_t; + type _trigger_cnt; + type _saved_event_cnt; + }; + + stats(client& client, handle::internal_handle_t endpoint_handle); + ~stats(); + + void set_data_format(const std::string& json_format) override; + void read_data(timeout_t timeout, std::va_list* args) override; + void has_data(timeout_t timeout) override; + void clear_data() override; + + void update(std::size_t channel, time_info::type timestamp, caen::optional time_info, caen::optional counter_info); + + static args_list_t default_data_format(); + static std::size_t data_format_dimension(names name); + + private: + + struct endpoint_impl; // forward declaration + std::unique_ptr _pimpl; + + }; + +private: + struct hit_evt { + struct s { + // 1st word + static constexpr std::size_t last_word{1}; // first bit of each word + static constexpr std::size_t channel{7}; + static constexpr std::size_t special_event{1}; + static constexpr std::size_t tbd_1{7}; + static constexpr std::size_t timestamp{48}; + static constexpr std::size_t timestamp_reduced{32}; + // 2nd word + static constexpr std::size_t has_waveform{1}; + static constexpr std::size_t flag_low_priority{12}; + static constexpr std::size_t flag_high_priority{8}; + static constexpr std::size_t energy_short{16}; + static constexpr std::size_t fine_timestamp{10}; + static constexpr std::size_t energy{16}; + // 3rd word (extra) + static constexpr std::size_t extra_type{3}; + static constexpr std::size_t extra_data{60}; + }; + enum struct extra_type : caen::uint_t::fast { + wave_info = 0b000, + time_info = 0b001, + counter_info = 0b010, + }; + struct wave_info_data { + struct digital_probe { + struct s { + // part of 3rd word (extra) + static constexpr std::size_t type{4}; + // part of waveform word + static constexpr std::size_t sample{1}; + }; + enum struct type : caen::uint_t::fast { + trigger = 0b0000, + time_filter_armed = 0b0001, + re_trigger_guard = 0b0010, + energy_filter_baseline_freeze = 0b0011, + over_threshold = 0b0100, + charge_ready = 0b0101, + long_gate = 0b0110, + event_pile_up = 0b0111, + short_gate = 0b1000, + input_saturation = 0b1001, + charge_over_range = 0b1010, + negative_over_threshold = 0b1011, + }; + // fields + type _type; + dpp_digital_probe_type _decoded_type; // decoded common type + caen::vector::least> _data; + }; + struct analog_probe { + struct s { + // part of 3rd word (extra) + static constexpr std::size_t mul_factor{2}; + static constexpr std::size_t is_signed{1}; + static constexpr std::size_t type{3}; + // part of waveform word + static constexpr std::size_t sample{14}; + static constexpr std::size_t decoded_sample{sample + 4}; // 4 is factor_16 + }; + enum struct mul_factor : caen::uint_t::fast { + factor_1 = 0b00, + factor_4 = 0b01, + factor_8 = 0b10, + factor_16 = 0b11, + }; + enum struct type : caen::uint_t::fast { + adc_input = 0b000, + baseline = 0b001, + cfd = 0b010, + }; + // fields + mul_factor _mul_factor; + bool _is_signed; + type _type; + dpp_analog_probe_type _decoded_type; // decoded common type + caen::vector::least> _data; + caen::vector::least> _decoded_data; + decltype(_decoded_data)::value_type _decoded_mul_factor; + }; + struct s { + // 3rd word (extra), other fields described in analog_probe::s and digital_probe::s + static constexpr std::size_t tbd_1{14}; + static constexpr std::size_t time_resolution{2}; + static constexpr std::size_t trigger_thr{16}; + // waveform size word + static constexpr std::size_t truncated{1}; + static constexpr std::size_t tbd_2{51}; + static constexpr std::size_t waveform_n_words{12}; + // waveform word + static constexpr std::size_t n_digital_probes{4}; + static constexpr std::size_t n_analog_probes{2}; + static constexpr std::size_t sample{n_analog_probes * analog_probe::s::sample + n_digital_probes * digital_probe::s::sample}; + }; + enum struct time_resolution : caen::uint_t::fast { + no_downsampling = 0b00, + downsampling_x2 = 0b01, + downsampling_x4 = 0b10, + downsampling_x8 = 0b11, + }; + // constants + static constexpr extra_type extra_id{extra_type::wave_info}; + static constexpr std::size_t samples_per_word{word_bit_size / s::sample}; + static constexpr std::size_t max_waveform_words{4095}; + static constexpr std::size_t max_waveform_samples{max_waveform_words * samples_per_word}; + // fields + // - tbd_1 not saved into event + time_resolution _time_resolution; + caen::uint_t::fast _trigger_thr; + std::array _digital_probes; + std::array _analog_probes; + // - truncated not saved into event + // - tbd_2 not saved into event + // - waveform_n_words not saved into event + }; + struct time_info_data { + struct s { + // 3rd word (extra) + static constexpr std::size_t tbd_1{12}; + static constexpr std::size_t dead_time{48}; + }; + // constants + static constexpr extra_type extra_id{extra_type::time_info}; + // fields + // - tbd_1 not saved into event + caen::uint_t::fast _dead_time; + }; + struct counter_info_data { + struct s { + static constexpr std::size_t tbd_1{12}; + static constexpr std::size_t trigger_cnt{24}; + static constexpr std::size_t saved_event_cnt{24}; + }; + // constants + static constexpr extra_type extra_id{extra_type::counter_info}; + // fields + // - tbd_1 not saved into event + caen::uint_t::fast _trigger_cnt; + caen::uint_t::fast _saved_event_cnt; + }; + // fields + caen::uint_t::fast _channel; + // - special_event not saved into event + // - tbd_1 not saved into event + caen::uint_t::fast _timestamp; + // - has_waveform not saved into event + caen::uint_t::fast _flag_low_priority; + caen::uint_t::fast _flag_high_priority; + caen::uint_t::fast _energy_short; + caen::uint_t::fast _fine_timestamp; + caen::uint_t::fast _energy; + // - extra_type not saved into event + // - extra_data not saved into event + wave_info_data _wave_info_data; + std::size_t _event_size; + // fields from aggregate header + bool _board_fail; + bool _flush; + caen::uint_t::fast _aggregate_counter; + // software fields + bool _fake_stop_event; + // consistency assertions + static_assert(std::is_same::value, "documented to be handled as std::uint8_t"); + static_assert(std::is_same::value, "documented to be handled as std::uint16_t"); + static_assert(std::is_same::value, "documented to be handled as std::int32_t"); + }; + + // decode internal implementation + void decode_hit(const caen::byte*& p); + void decode_hit_waveform(const caen::byte*& p, hit_evt::wave_info_data& ed); + + struct endpoint_impl; // forward declaration + std::unique_ptr _pimpl; + + std::shared_ptr _stats_ep; + +}; + +using namespace std::string_literals; + +NLOHMANN_JSON_SERIALIZE_ENUM(dpppsd::names, { + { dpppsd::names::UNKNOWN, nullptr }, + { dpppsd::names::CHANNEL, "CHANNEL"s }, + { dpppsd::names::TIMESTAMP, "TIMESTAMP"s }, + { dpppsd::names::TIMESTAMP_NS, "TIMESTAMP_NS"s }, + { dpppsd::names::FINE_TIMESTAMP, "FINE_TIMESTAMP"s }, + { dpppsd::names::ENERGY, "ENERGY"s }, + { dpppsd::names::ENERGY_SHORT, "ENERGY_SHORT"s }, + { dpppsd::names::FLAGS_LOW_PRIORITY, "FLAGS_LOW_PRIORITY"s }, + { dpppsd::names::FLAGS_HIGH_PRIORITY, "FLAGS_HIGH_PRIORITY"s }, + { dpppsd::names::TRIGGER_THR, "TRIGGER_THR"s }, + { dpppsd::names::TIME_RESOLUTION, "TIME_RESOLUTION"s }, + { dpppsd::names::ANALOG_PROBE_1, "ANALOG_PROBE_1"s }, + { dpppsd::names::ANALOG_PROBE_1_TYPE, "ANALOG_PROBE_1_TYPE"s }, + { dpppsd::names::ANALOG_PROBE_2, "ANALOG_PROBE_2"s }, + { dpppsd::names::ANALOG_PROBE_2_TYPE, "ANALOG_PROBE_2_TYPE"s }, + { dpppsd::names::DIGITAL_PROBE_1, "DIGITAL_PROBE_1"s }, + { dpppsd::names::DIGITAL_PROBE_1_TYPE, "DIGITAL_PROBE_1_TYPE"s }, + { dpppsd::names::DIGITAL_PROBE_2, "DIGITAL_PROBE_2"s }, + { dpppsd::names::DIGITAL_PROBE_2_TYPE, "DIGITAL_PROBE_2_TYPE"s }, + { dpppsd::names::DIGITAL_PROBE_3, "DIGITAL_PROBE_3"s }, + { dpppsd::names::DIGITAL_PROBE_3_TYPE, "DIGITAL_PROBE_3_TYPE"s }, + { dpppsd::names::DIGITAL_PROBE_4, "DIGITAL_PROBE_4"s }, + { dpppsd::names::DIGITAL_PROBE_4_TYPE, "DIGITAL_PROBE_4_TYPE"s }, + { dpppsd::names::WAVEFORM_SIZE, "WAVEFORM_SIZE"s }, + { dpppsd::names::BOARD_FAIL, "BOARD_FAIL"s }, + { dpppsd::names::AGGREGATE_COUNTER, "AGGREGATE_COUNTER"s }, + { dpppsd::names::FLUSH, "FLUSH"s }, + { dpppsd::names::EVENT_SIZE, "EVENT_SIZE"s }, +}) + +NLOHMANN_JSON_SERIALIZE_ENUM(dpppsd::stats::names, { + { dpppsd::stats::names::UNKNOWN, nullptr }, + { dpppsd::stats::names::REAL_TIME, "REAL_TIME"s }, + { dpppsd::stats::names::REAL_TIME_NS, "REAL_TIME_NS"s }, + { dpppsd::stats::names::DEAD_TIME, "DEAD_TIME"s }, + { dpppsd::stats::names::DEAD_TIME_NS, "DEAD_TIME_NS"s }, + { dpppsd::stats::names::LIVE_TIME, "LIVE_TIME"s }, + { dpppsd::stats::names::LIVE_TIME_NS, "LIVE_TIME_NS"s }, + { dpppsd::stats::names::TRIGGER_CNT, "TRIGGER_CNT"s }, + { dpppsd::stats::names::SAVED_EVENT_CNT, "SAVED_EVENT_CNT"s }, +}) + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_DPPPSD_HPP_ */ diff --git a/include/endpoints/dppzle.hpp b/include/endpoints/dppzle.hpp new file mode 100644 index 0000000..5690ca9 --- /dev/null +++ b/include/endpoints/dppzle.hpp @@ -0,0 +1,225 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file dppzle.hpp +* \brief Decoded endpoint for DPP-ZLE +* \author Giovanni Cerretani, Stefano Venditti +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_DPPZLE_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_DPPZLE_HPP_ + +#include +#include +#include +#include + +#include + +#include "cpp-utility/integer.hpp" +#include "cpp-utility/vector.hpp" +#include "endpoints/aggregate_endpoint.hpp" + +namespace caen { + +namespace dig2 { + +namespace ep { + +struct dppzle final : public aggregate_endpoint { + + enum class names { // overrides endpoint::names + UNKNOWN, + TIMESTAMP, + TIMESTAMP_NS, + RECORD_LENGTH, + TRUNCATE_WAVE, + TRUNCATE_PARAM, + WAVEFORM_DEFVALUE, + CHUNK_NUMBER, + CHUNK_TIME, + CHUNK_SIZE, + CHUNK_BEGIN, + WAVEFORM, + RECONSTRUCTED_WAVEFORM, + SAMPLE_TYPE, + RECONSTRUCTED_WAVEFORM_SIZE, + BOARD_FAIL, + AGGREGATE_COUNTER, + FLUSH, + EVENT_SIZE, + }; + + using args_list_t = utility::args_list_t; + + dppzle(client& client, handle::internal_handle_t endpoint_handle); + ~dppzle(); + + void resize() override; + void decode(const caen::byte* p, std::size_t size) override; + void stop() override; + void set_data_format(const std::string &json_format) override; + void read_data(timeout_t timeout, std::va_list* args) override; + void has_data(timeout_t timeout) override; + void clear_data() override; + + static args_list_t default_data_format(); + static std::size_t data_format_dimension(names name); + +private: + struct zle_evt { + struct s { + // 1st word + static constexpr std::size_t last_word{1}; // first bit of each word + static constexpr std::size_t channel{7}; + static constexpr std::size_t last_channel{1}; + static constexpr std::size_t tbd_1{7}; + static constexpr std::size_t timestamp{48}; + // 2nd word (half word) + static constexpr std::size_t has_waveform{1}; + static constexpr std::size_t tbd_2{10}; + static constexpr std::size_t waveform_defvalue{16}; + static constexpr std::size_t tbd_3{3}; + static constexpr std::size_t even_counters_good{1}; + // tbd_4 is the unused half word (last high half word in case of even counters) + static constexpr std::size_t tbd_4{31}; + // waveform size word + static constexpr std::size_t truncated{1}; + static constexpr std::size_t tbd_5{51}; + static constexpr std::size_t waveform_n_words{12}; + // waveform + static constexpr std::size_t sample{16}; + }; + struct counter { + struct s { + // counter (half word) + static constexpr std::size_t tbd_1{1}; // bit occupied by last_word on even counters + static constexpr std::size_t last{1}; + static constexpr std::size_t wave_truncated{1}; + static constexpr std::size_t counters_truncated{1}; + static constexpr std::size_t size{28}; + }; + // - tbd_1 not saved into event + bool _last; + bool _wave_truncated; + bool _counters_truncated; + caen::uint_t::fast _size; + bool _is_good; + }; + struct channel_data { + // typedefs + using waveform_t = caen::vector::least>; + // fields + bool _truncate_wave; + bool _truncate_param; + caen::uint_t::fast _waveform_defvalue; // saved for each channel + caen::vector _chunk_time; + caen::vector _chunk_size; + caen::vector _chunk_begin; + waveform_t _waveform; + waveform_t _reconstructed_waveform; + caen::vector::least> _sample_type; // software probe (better to avoid vector) + }; + // constants + static constexpr std::size_t samples_per_word{word_bit_size / s::sample}; + static constexpr std::size_t max_n_counters{1023}; + static constexpr std::size_t max_waveform_words{4095}; + static constexpr std::size_t max_waveform_samples{max_waveform_words * samples_per_word}; + // fields + // - channel not saved into event + // - last_channel not saved into event + // - tbd_1 not saved into event + caen::uint_t::fast _timestamp; + // - has_waveform not saved into event + // - tbd_2 not saved into event + // - waveform_defvalue saved per channel + // - tbd_3 not saved into event + // - even_counters_good not saved into event + caen::vector _counters; + // - tbd_4 not saved into event + // - truncated not saved into event + // - tbd_5 not saved into event + // - waveform_n_words not saved into event + std::size_t _record_length; + caen::vector _channel_data; + std::size_t _event_size; + // fields from aggregate header + bool _board_fail; + bool _flush; + caen::uint_t::fast _aggregate_counter; + // software fields + bool _fake_stop_event; + // consistency assertions + static_assert(std::is_same::value, "documented to be handled as std::uint16_t"); + static_assert(std::is_same::value, "documented to be handled as std::uint16_t"); + static_assert(std::is_same::value, "documented to be handled as std::uint8_t"); + }; + + // decode internal implementation + void decode_hit(const caen::byte*& p); + void decode_hit_waveform(const caen::byte*& p, zle_evt::channel_data::waveform_t& waveform); + + struct endpoint_impl; // forward declaration + std::unique_ptr _pimpl; + +}; + +using namespace std::string_literals; + +NLOHMANN_JSON_SERIALIZE_ENUM(dppzle::names, { + { dppzle::names::UNKNOWN, nullptr }, + { dppzle::names::TIMESTAMP, "TIMESTAMP"s }, + { dppzle::names::TIMESTAMP_NS, "TIMESTAMP_NS"s }, + { dppzle::names::RECORD_LENGTH, "RECORD_LENGTH"s }, + { dppzle::names::TRUNCATE_WAVE, "TRUNCATE_WAVE"s }, + { dppzle::names::TRUNCATE_PARAM, "TRUNCATE_PARAM"s }, + { dppzle::names::WAVEFORM_DEFVALUE, "WAVEFORM_DEFVALUE"s }, + { dppzle::names::CHUNK_NUMBER, "CHUNK_NUMBER"s }, + { dppzle::names::CHUNK_TIME, "CHUNK_TIME"s }, + { dppzle::names::CHUNK_SIZE, "CHUNK_SIZE"s }, + { dppzle::names::CHUNK_BEGIN, "CHUNK_BEGIN"s }, + { dppzle::names::WAVEFORM, "WAVEFORM"s }, + { dppzle::names::RECONSTRUCTED_WAVEFORM, "RECONSTRUCTED_WAVEFORM"s }, + { dppzle::names::SAMPLE_TYPE, "SAMPLE_TYPE"s }, + { dppzle::names::RECONSTRUCTED_WAVEFORM_SIZE, "RECONSTRUCTED_WAVEFORM_SIZE"s }, + { dppzle::names::BOARD_FAIL, "BOARD_FAIL"s }, + { dppzle::names::AGGREGATE_COUNTER, "AGGREGATE_COUNTER"s }, + { dppzle::names::FLUSH, "FLUSH"s }, + { dppzle::names::EVENT_SIZE, "EVENT_SIZE"s }, +}) + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_SCOPE_HPP_ */ diff --git a/include/endpoints/endpoint.hpp b/include/endpoints/endpoint.hpp new file mode 100644 index 0000000..bc2f105 --- /dev/null +++ b/include/endpoints/endpoint.hpp @@ -0,0 +1,378 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file endpoint.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_ENDPOINT_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_ENDPOINT_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cpp-utility/args.hpp" +#include "cpp-utility/byte.hpp" +#include "cpp-utility/type_traits.hpp" +#include "cpp-utility/vector.hpp" +#include "lib_definitions.hpp" +#include "lib_error.hpp" + +namespace caen { + +namespace dig2 { + +struct client; // forward declaration + +namespace ep { + +struct endpoint : private boost::noncopyable { + + enum class names; // to be defined in child class + enum class types { + UNKNOWN, + U64, + U32, + U16, + U8, + I64, + I32, + I16, + I8, + CHAR, + BOOL, + SIZE_T, + PTRDIFF_T, + FLOAT, + DOUBLE, + LONG_DOUBLE, + }; + + using timeout_t = std::chrono::duration; + + endpoint(client& client, handle::internal_handle_t endpoint_server_handle); + virtual ~endpoint(); + + handle::internal_handle_t get_endpoint_server_handle() const noexcept; + client& get_client() const noexcept; // requires #include "client.hpp" to be used + + virtual void set_data_format(const std::string &json_format) = 0; + virtual void read_data(timeout_t timeout, std::va_list* args) = 0; + virtual void has_data(timeout_t timeout) = 0; + virtual void clear_data() = 0; + +private: + + struct endpoint_impl; // forward declaration + std::unique_ptr _pimpl; + +}; + +BOOST_STATIC_ASSERT(std::is_abstract::value); +BOOST_STATIC_ASSERT(std::has_virtual_destructor::value); + +using namespace std::string_literals; + +NLOHMANN_JSON_SERIALIZE_ENUM(endpoint::types, { + { endpoint::types::UNKNOWN, nullptr }, + { endpoint::types::U64, "U64"s }, + { endpoint::types::U32, "U32"s }, + { endpoint::types::U16, "U16"s }, + { endpoint::types::U8, "U8"s }, + { endpoint::types::I64, "I64"s }, + { endpoint::types::I32, "I32"s }, + { endpoint::types::I16, "I16"s }, + { endpoint::types::I8, "I8"s }, + { endpoint::types::CHAR, "CHAR"s }, + { endpoint::types::BOOL, "BOOL"s }, + { endpoint::types::SIZE_T, "SIZE_T"s }, + { endpoint::types::PTRDIFF_T, "PTRDIFF_T"s }, + { endpoint::types::FLOAT, "FLOAT"s }, + { endpoint::types::DOUBLE, "DOUBLE"s }, + { endpoint::types::LONG_DOUBLE, "LONG DOUBLE"s }, // deliberately using space instead of underscore +}) + +namespace utility { + +namespace detail { + +using tp = endpoint::types; + +template struct ref_type {}; // default case (compile time error) +template <> struct ref_type { using type = std::uint8_t; }; +template <> struct ref_type { using type = std::uint16_t; }; +template <> struct ref_type { using type = std::uint32_t; }; +template <> struct ref_type { using type = std::uint64_t; }; +template <> struct ref_type { using type = std::int8_t; }; +template <> struct ref_type { using type = std::int16_t; }; +template <> struct ref_type { using type = std::int32_t; }; +template <> struct ref_type { using type = std::int64_t; }; +template <> struct ref_type { using type = char; }; +template <> struct ref_type { using type = bool; }; +template <> struct ref_type { using type = std::size_t; }; +template <> struct ref_type { using type = std::ptrdiff_t; }; +template <> struct ref_type { using type = float; }; +template <> struct ref_type { using type = double; }; +template <> struct ref_type { using type = long double; }; + +template +using ref_type_t = typename ref_type::type; + +// default case (compile time error) +template +struct insert_value_helper {}; + +template <> +struct insert_value_helper<0> { + template + static void insert(Args&&... args) noexcept { + caen::args::insert_value>(std::forward(args)...); + } +}; +template <> +struct insert_value_helper<1> { + template + static void insert(Args&&... args) noexcept { + caen::args::insert_array>(std::forward(args)...); + } +}; +template <> +struct insert_value_helper<2> { + template + static void insert(Args&&... args) noexcept { + caen::args::insert_matrix>(std::forward(args)...); + } +}; + +template +void put_argument_generic(std::va_list* args, endpoint::types t, Args&&... value) { + switch (t) { + using tp = endpoint::types; + using ivh = insert_value_helper; + case tp::U64: return ivh::template insert(args, std::forward(value)...); + case tp::U32: return ivh::template insert(args, std::forward(value)...); + case tp::U16: return ivh::template insert(args, std::forward(value)...); + case tp::U8: return ivh::template insert(args, std::forward(value)...); + case tp::I64: return ivh::template insert(args, std::forward(value)...); + case tp::I32: return ivh::template insert(args, std::forward(value)...); + case tp::I16: return ivh::template insert(args, std::forward(value)...); + case tp::I8: return ivh::template insert(args, std::forward(value)...); + case tp::CHAR: return ivh::template insert(args, std::forward(value)...); + case tp::BOOL: return ivh::template insert(args, std::forward(value)...); + case tp::SIZE_T: return ivh::template insert(args, std::forward(value)...); + case tp::PTRDIFF_T: return ivh::template insert(args, std::forward(value)...); + case tp::FLOAT: return ivh::template insert(args, std::forward(value)...); + case tp::DOUBLE: return ivh::template insert(args, std::forward(value)...); + case tp::LONG_DOUBLE: return ivh::template insert(args, std::forward(value)...); + default: throw ex::invalid_argument("invalid type"); + } +} + +} // detail namespace + +template +void put_argument(std::va_list *args, endpoint::types t, TIn&& value) { + detail::put_argument_generic<0>(args, t, std::forward(value)); +} + +template +void put_argument_raw_data(std::va_list *args, endpoint::types t, const TIn* p, std::size_t size) { + switch (t) { + using tp = endpoint::types; + using namespace detail; + case tp::U8: + caen::args::insert_raw_data(args, p, size); + break; + default: + throw ex::invalid_argument("invalid type"); + } +} + +// Container is a container +template +void put_argument_array(std::va_list *args, endpoint::types t, const Container& value) { + detail::put_argument_generic<1>(args, t, value); +} + +// Container is a container of containers +template +void put_argument_matrix(std::va_list *args, endpoint::types t, const Container& value) { + detail::put_argument_generic<2>(args, t, value); +} + +namespace detail { + +template +struct is_names_defined : std::false_type {}; +template +struct is_names_defined> : std::is_enum {}; + +template +struct is_types_defined : std::false_type {}; +template +struct is_types_defined> : std::is_enum {}; + +template +struct is_args_list_t_defined : std::false_type {}; +template +struct is_args_list_t_defined> : std::true_type {}; + +template +struct is_unknown_defined : std::false_type {}; +template +struct is_unknown_defined> : std::is_enum {}; + +template +struct is_type_any_of : caen::disjunction...> {}; + +namespace sanity_checks { + +struct foo { + enum class names; + using types = int; +}; + +constexpr bool test_is_defined() noexcept { + bool ret{true}; + ret &= (is_names_defined::value); // true even if opaque + ret &= (!is_types_defined::value); // not an enum + ret &= (!is_args_list_t_defined::value); + ret &= (is_names_defined::value); + ret &= (is_types_defined::value); + ret &= (!is_args_list_t_defined::value); + ret &= (!is_unknown_defined::value); + ret &= (is_unknown_defined::value); + return ret; +} + +constexpr bool test_is_type_any_of() noexcept { + bool ret{true}; + ret &= (is_type_any_of::value); + ret &= (!is_type_any_of::value); + return ret; +} + +BOOST_STATIC_ASSERT(test_is_defined()); +BOOST_STATIC_ASSERT(test_is_type_any_of()); + +} // namespace sanity_checks + +} // namespace detail + +/** + * @brief Endpoint traits. + * + * Typically, traits are not useful for derived class. However C++ does not support inheritance and override of types, + * So, traits in our case can be used to specify that each endpoint specialization must have an enumerator + * named "names" containing at least "UNKNOWN". The other enumeration "types" must be inherited from base enum, that contains "UNKNOWN". + * This is used in json_data_format class for serialization. + * @tparam Endpoint the endpoint type + */ +template +struct endpoint_traits { + + // static assertions + static_assert(boost::is_complete::value, "endpoint_traits requires a complete type (see args_list)"); + static_assert(detail::is_names_defined::value, "endpoint must define names"); + static_assert(detail::is_types_defined::value, "endpoint must define types"); + static_assert(detail::is_args_list_t_defined::value, "endpoint must define args_list_t"); + + // public definitions + using names_type = typename Endpoint::names; + using types_type = typename Endpoint::types; + using args_list_type = typename Endpoint::args_list_t; + + // more static assertions + static_assert(std::is_base_of::value, "invalid endpoint type"); + static_assert(std::is_same::value, "types cannot be overridden"); + static_assert(detail::is_unknown_defined::value, "names must define UNKNOWN"); + static_assert(detail::is_unknown_defined::value, "types must define UNKNOWN"); + + // utility function to check if value is unknown for both names and types + template + static constexpr bool is_unknown(Enum v) noexcept { + static_assert(detail::is_type_any_of::value, "invalid enum type"); + return v == Enum::UNKNOWN; + } + +}; + +/** + * @brief Args list generator. + * + * Used to define a member of endpoint classes, we cannot use Endpoint as template argument + * since type it is still incomplete if used in the class definition. + * @sa https://stackoverflow.com/q/71717523/3287591 + * @tparam Names names enumerator, that is endpoint specific + * @tparam Types types enumerator (could also be replaced directly with endpont::types since endpoints cannot override it) + */ +template +struct args_list { + + // public definitions + using names_type = Names; + using types_type = Types; + + // static assertions + static_assert(std::is_same::value, "types cannot be overridden"); + static_assert(detail::is_unknown_defined::value, "names must define UNKNOWN"); + static_assert(detail::is_unknown_defined::value, "types must define UNKNOWN"); + + // public definitions + using type = caen::vector>; + +}; + +template +using args_list_t = typename args_list::type; + +} // namespace utility + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_ENDPOINT_HPP_ */ diff --git a/include/endpoints/events.hpp b/include/endpoints/events.hpp new file mode 100644 index 0000000..33f0e1a --- /dev/null +++ b/include/endpoints/events.hpp @@ -0,0 +1,160 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file events.hpp +* \brief Special event endpoint +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_EVENTS_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_EVENTS_HPP_ + +#include +#include +#include +#include + +#include "cpp-utility/variant.hpp" +#include "cpp-utility/vector.hpp" +#include "endpoints/sw_endpoint.hpp" +#include "library_logger.hpp" + +namespace caen { + +namespace dig2 { + +namespace ep { + +struct hw_endpoint; // forward declaration + +struct events final : public sw_endpoint { + + enum class names { UNKNOWN }; // overrides endpoint::names + + events(client& client, hw_endpoint& parent_endpoint); + ~events(); + + void resize() override; + void decode(const caen::byte* p, std::size_t size) override; + void stop() override; + void set_data_format(const std::string &json_format) override; + void read_data(timeout_t timeout, std::va_list* args) override; + void has_data(timeout_t timeout) override; + void clear_data() override; + +private: + struct special_evt { + struct s { + // 1st header + static constexpr std::size_t format{evt_header::s::format}; + static constexpr std::size_t event_id{4}; + static constexpr std::size_t tdb_1{16}; + static constexpr std::size_t n_additional_headers{8}; + static constexpr std::size_t n_words{evt_header::s::n_words}; + static_assert(event_id + tdb_1 + n_additional_headers == evt_header::s::implementation_defined, "invalid sizes"); + // other headers + static constexpr std::size_t additional_header_type{8}; + static constexpr std::size_t additional_header_data{56}; + }; + enum struct event_id_type : caen::uint_t::fast { + start = 0b0000, + stop = 0b0010, + }; + enum struct additional_header_type_type : caen::uint_t::fast { + size_48 = 0b00000000, + size_32 = 0b00000001, + acq_width = 0b00000010, + }; + struct additional_header { + additional_header_type_type _type; + caen::uint_t::fast _data; + }; + struct start_event_data { + static constexpr event_id_type event_id{event_id_type::start}; + static constexpr std::size_t n_additional_headers{3}; + struct s { + static constexpr std::size_t tbd_1{24}; + static constexpr std::size_t decimation_factor_log2{5}; + static constexpr std::size_t n_traces{2}; + static constexpr std::size_t acq_width{25}; + static constexpr std::size_t tbd_2{24}; + static constexpr std::size_t ch_mask_31_0{32}; + static constexpr std::size_t tbd_3{24}; + static constexpr std::size_t ch_mask_63_32{32}; + }; + // - tbd_1 not saved into event + caen::uint_t::fast _decimation_factor_log2; + caen::uint_t::fast _n_traces; + caen::uint_t::fast _acq_width; + // - tbd_2 not saved into event + caen::uint_t::fast _ch_mask_31_0; + // - tbd_3 not saved into event + caen::uint_t::fast _ch_mask_63_32; + }; + struct stop_event_data { + static constexpr event_id_type event_id{event_id_type::stop}; + static constexpr std::size_t n_additional_headers{2}; + struct s { + static constexpr std::size_t tbd_1{8}; + static constexpr std::size_t evt_time_tag{48}; + static constexpr std::size_t tbd_2{24}; + static constexpr std::size_t dead_time{32}; + }; + // - tbd_1 not saved into event + caen::uint_t::fast _evt_time_tag; + // - tbd_2 not saved into event + caen::uint_t::fast _dead_time; + }; + evt_header::format _format; + event_id_type _event_id; + // - tbd_1 not saved into event + caen::uint_t::fast _n_additional_headers; + caen::uint_t::fast _n_words; + caen::vector _additional_headers; + caen::variant _event_data; + }; + + std::shared_ptr _logger; + hw_endpoint& _hw_endpoint; + std::list> _args_list; +}; + +NLOHMANN_JSON_SERIALIZE_ENUM(events::names, { + { events::names::UNKNOWN, nullptr } +}) + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_EVENTS_HPP_ */ diff --git a/include/endpoints/hw_endpoint.hpp b/include/endpoints/hw_endpoint.hpp new file mode 100644 index 0000000..e819809 --- /dev/null +++ b/include/endpoints/hw_endpoint.hpp @@ -0,0 +1,80 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file hw_endpoint.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_HW_ENDPOINT_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_HW_ENDPOINT_HPP_ + +#include + +#include "endpoints/endpoint.hpp" + +namespace caen { + +namespace dig2 { + +struct client; // forward declaration + +namespace ep { + +struct sw_endpoint; // forward declaration + +struct hw_endpoint : public endpoint { + + hw_endpoint(client& client, handle::internal_handle_t endpoint_handle); + ~hw_endpoint(); + + virtual void register_sw_endpoint(std::shared_ptr ep) = 0; + + virtual void arm_acquisition() = 0; + virtual void disarm_acquisition() = 0; + + virtual void event_start() = 0; + virtual void event_stop() = 0; + +private: + + struct endpoint_impl; + std::unique_ptr _pimpl; + +}; + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_HW_ENDPOINT_HPP_ */ diff --git a/include/endpoints/opendpp.hpp b/include/endpoints/opendpp.hpp new file mode 100644 index 0000000..82644d4 --- /dev/null +++ b/include/endpoints/opendpp.hpp @@ -0,0 +1,196 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file opendpp.hpp +* \brief Decoded endpoint for Open DPP +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_OPENDPP_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_OPENDPP_HPP_ + +#include +#include +#include +#include + +#include + +#include "cpp-utility/integer.hpp" +#include "cpp-utility/vector.hpp" +#include "endpoints/aggregate_endpoint.hpp" + +namespace caen { + +namespace dig2 { + +namespace ep { + +struct opendpp final : public aggregate_endpoint { + + enum class names { // overrides endpoint::names + UNKNOWN, + CHANNEL, + TIMESTAMP, + TIMESTAMP_NS, + FINE_TIMESTAMP, + ENERGY, + FLAGS_B, + FLAGS_A, + PSD, + SPECIAL_EVENT, + USER_INFO, + USER_INFO_SIZE, + TRUNCATED, + WAVEFORM, + WAVEFORM_SIZE, + BOARD_FAIL, + AGGREGATE_COUNTER, + FLUSH, + EVENT_SIZE, + }; + + using args_list_t = utility::args_list_t; + + opendpp(client& client, handle::internal_handle_t endpoint_handle); + ~opendpp(); + + void resize() override; + void decode(const caen::byte* p, std::size_t size) override; + void stop() override; + void set_data_format(const std::string &json_format) override; + void read_data(timeout_t timeout, std::va_list* args) override; + void has_data(timeout_t timeout) override; + void clear_data() override; + + static args_list_t default_data_format(); + static std::size_t data_format_dimension(names name); + +private: + struct hit_evt { + struct s { + // 1st word + static constexpr std::size_t last_word{1}; // first bit of each word + static constexpr std::size_t channel{7}; + static constexpr std::size_t special_event{1}; + static constexpr std::size_t info{7}; + static constexpr std::size_t timestamp{48}; + static constexpr std::size_t timestamp_reduced{32}; + // 2nd word + static constexpr std::size_t has_waveform{1}; + static constexpr std::size_t flags_b{12}; + static constexpr std::size_t flags_a{8}; + static constexpr std::size_t psd{16}; + static constexpr std::size_t fine_timestamp{10}; + static constexpr std::size_t energy{16}; + // nth word (user info) + static constexpr std::size_t user_info{63}; + // waveform size word + static constexpr std::size_t truncated{1}; + static constexpr std::size_t tbd_1{51}; + static constexpr std::size_t waveform_n_words{12}; + // waveform + static constexpr std::size_t sample{16}; + }; + // constants + static constexpr std::size_t samples_per_word{word_bit_size / s::sample}; + static constexpr std::size_t max_user_info_words{4}; + static constexpr std::size_t max_waveform_words{4095}; + static constexpr std::size_t max_waveform_samples{max_waveform_words * samples_per_word}; + // typedefs + using waveform_t = caen::vector::least>; + // fields + caen::uint_t::fast _channel; + bool _special_event; + caen::uint_t::fast _info; + caen::uint_t::fast _timestamp; + // - has_waveform not saved into event + caen::uint_t::fast _flags_b; + caen::uint_t::fast _flags_a; + caen::uint_t::fast _psd; + caen::uint_t::fast _fine_timestamp; + caen::uint_t::fast _energy; + caen::vector::fast> _user_info; + // - tbd_1 not saved into event + bool _truncated; + // - waveform_n_words not saved into event + waveform_t _waveform; + std::size_t _event_size; + // fields from aggregate header + bool _board_fail; + bool _flush; + caen::uint_t::fast _aggregate_counter; + // software fields + bool _fake_stop_event; + // consistency assertions + static_assert(std::is_same::value, "documented to be handled as std::uint16_t"); + }; + + // decode internal implementation + void decode_hit(const caen::byte*& p); + void decode_hit_waveform(const caen::byte*& p, hit_evt::waveform_t& waveform, bool& truncated); + + struct endpoint_impl; + std::unique_ptr _pimpl; + +}; + +using namespace std::string_literals; + +NLOHMANN_JSON_SERIALIZE_ENUM(opendpp::names, { + { opendpp::names::UNKNOWN, nullptr }, + { opendpp::names::CHANNEL, "CHANNEL"s }, + { opendpp::names::TIMESTAMP, "TIMESTAMP"s }, + { opendpp::names::TIMESTAMP_NS, "TIMESTAMP_NS"s }, + { opendpp::names::FINE_TIMESTAMP, "FINE_TIMESTAMP"s }, + { opendpp::names::ENERGY, "ENERGY"s }, + { opendpp::names::FLAGS_B, "FLAGS_B"s }, + { opendpp::names::FLAGS_A, "FLAGS_A"s }, + { opendpp::names::PSD, "PSD"s }, + { opendpp::names::SPECIAL_EVENT, "SPECIAL_EVENT"s }, + { opendpp::names::USER_INFO, "USER_INFO"s }, + { opendpp::names::USER_INFO_SIZE, "USER_INFO_SIZE"s }, + { opendpp::names::TRUNCATED, "TRUNCATED"s }, + { opendpp::names::WAVEFORM, "WAVEFORM"s }, + { opendpp::names::WAVEFORM_SIZE, "WAVEFORM_SIZE"s }, + { opendpp::names::BOARD_FAIL, "BOARD_FAIL"s }, + { opendpp::names::AGGREGATE_COUNTER, "AGGREGATE_COUNTER"s }, + { opendpp::names::FLUSH, "FLUSH"s }, + { opendpp::names::EVENT_SIZE, "EVENT_SIZE"s }, +}) + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_OPENDPP_HPP_ */ diff --git a/include/endpoints/raw.hpp b/include/endpoints/raw.hpp new file mode 100644 index 0000000..a8837b6 --- /dev/null +++ b/include/endpoints/raw.hpp @@ -0,0 +1,108 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file raw.hpp +* \brief Raw endpoint +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_RAW_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_RAW_HPP_ + +#include +#include +#include +#include + +#include "endpoints/hw_endpoint.hpp" + +namespace caen { + +namespace dig2 { + +namespace ep { + +struct sw_endpoint; // forward declaration + +struct raw final : public hw_endpoint { + + enum class names { // overrides endpoint::names + UNKNOWN, + DATA, + SIZE, + N_EVENTS, + }; + + using args_list_t = utility::args_list_t; + + raw(client& client, handle::internal_handle_t endpoint_handle); + ~raw(); + + void set_max_size_getter(std::function f); + void set_is_decoded_getter(std::function f); + + void register_sw_endpoint(std::shared_ptr ep) override; + void set_data_format(const std::string& json_format) override; + void read_data(timeout_t timeout, std::va_list* args) override; + void has_data(timeout_t timeout) override; + void clear_data() override; + void arm_acquisition() override; + void disarm_acquisition() override; + + void event_start() override; + void event_stop() override; + + static args_list_t default_data_format(); + static std::size_t data_format_dimension(names name); + +private: + + struct endpoint_impl; + std::unique_ptr _pimpl; + +}; + +using namespace std::string_literals; + +NLOHMANN_JSON_SERIALIZE_ENUM(raw::names, { + { raw::names::UNKNOWN, nullptr }, + { raw::names::DATA, "DATA"s }, + { raw::names::SIZE, "SIZE"s }, + { raw::names::N_EVENTS, "N_EVENTS"s }, +}) + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_RAW_HPP_ */ diff --git a/include/endpoints/rawudp.hpp b/include/endpoints/rawudp.hpp new file mode 100644 index 0000000..59e9e2f --- /dev/null +++ b/include/endpoints/rawudp.hpp @@ -0,0 +1,110 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file rawudp.hpp +* \brief Raw UDP endpoint +* \author Giovanni Cerretani, Alberto Potenza +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_RAWUDP_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_RAWUDP_HPP_ + +#include +#include +#include +#include + +#include "endpoints/hw_endpoint.hpp" + +namespace caen { + +namespace dig2 { + +namespace ep { + +struct sw_endpoint; // forward declaration + +struct rawudp final : public hw_endpoint { + + enum class names { // overrides endpoint::names + UNKNOWN, + DATA, + SIZE, + BUFFER_ID, + FLUSH, + }; + + using args_list_t = utility::args_list_t; + + rawudp(client& client, handle::internal_handle_t endpoint_handle); + ~rawudp(); + + void set_max_size_getter(std::function f); + void set_is_decoded_getter(std::function f); + + void register_sw_endpoint(std::shared_ptr ep) override; + void set_data_format(const std::string& json_format) override; + void read_data(timeout_t timeout, std::va_list* args) override; + void has_data(timeout_t timeout) override; + void clear_data() override; + void arm_acquisition() override; + void disarm_acquisition() override; + + void event_start() override; + void event_stop() override; + + static args_list_t default_data_format(); + static std::size_t data_format_dimension(names name); + +private: + + struct endpoint_impl; + std::unique_ptr _pimpl; + +}; + +using namespace std::string_literals; + +NLOHMANN_JSON_SERIALIZE_ENUM(rawudp::names, { + { rawudp::names::UNKNOWN, nullptr }, + { rawudp::names::DATA, "DATA"s }, + { rawudp::names::SIZE, "SIZE"s }, + { rawudp::names::BUFFER_ID, "BUFFER_ID"s }, + { rawudp::names::FLUSH, "FLUSH"s }, +}) + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_RA_UDP_HPP_ */ diff --git a/include/endpoints/scope.hpp b/include/endpoints/scope.hpp new file mode 100644 index 0000000..0b37d91 --- /dev/null +++ b/include/endpoints/scope.hpp @@ -0,0 +1,155 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file scope.hpp +* \brief Decoded endpoint for Scope +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_SCOPE_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_SCOPE_HPP_ + +#include +#include +#include +#include + +#include + +#include "cpp-utility/integer.hpp" +#include "cpp-utility/vector.hpp" +#include "endpoints/sw_endpoint.hpp" + +namespace caen { + +namespace dig2 { + +namespace ep { + +struct scope final : public sw_endpoint { + + enum class names { // overrides endpoint::names + UNKNOWN, + TIMESTAMP, + TIMESTAMP_NS, + TRIGGER_ID, + WAVEFORM, + WAVEFORM_SIZE, + FLAGS, + SAMPLES_OVERLAPPED, + BOARD_FAIL, + EVENT_SIZE, + }; + + using args_list_t = utility::args_list_t; + + scope(client& client, handle::internal_handle_t endpoint_handle); + ~scope(); + + void resize() override; + void decode(const caen::byte* p, std::size_t size) override; + void stop() override; + void set_data_format(const std::string &json_format) override; + void read_data(timeout_t timeout, std::va_list* args) override; + void has_data(timeout_t timeout) override; + void clear_data() override; + + static args_list_t default_data_format(); + static std::size_t data_format_dimension(names name); + +private: + struct scope_evt { + struct s { + // 1st word + static constexpr std::size_t format{evt_header::s::format}; + static constexpr std::size_t tbd_1{3}; + static constexpr std::size_t board_fail{1}; + static constexpr std::size_t trigger_id{24}; + static constexpr std::size_t n_words{evt_header::s::n_words}; + static_assert(tbd_1 + board_fail + trigger_id == evt_header::s::implementation_defined, "invalid sizes"); + // 2nd word + static constexpr std::size_t flags{13}; + static constexpr std::size_t samples_overlapped{3}; + static constexpr std::size_t timestamp{48}; + // 3rd word + static constexpr std::size_t ch_mask{64}; + // waveform word + static constexpr std::size_t sample{16}; + }; + // constants + static constexpr std::size_t evt_header_words{3}; + static constexpr std::size_t evt_header_size{evt_header_words * word_size}; + static constexpr std::size_t samples_per_word{word_bit_size / s::sample}; + // fields + evt_header::format _format; + // - tbd_1 not saved into event + bool _board_fail; + caen::uint_t::fast _trigger_id; + caen::uint_t::fast _n_words; + caen::uint_t::fast _flags; + caen::uint_t::fast _samples_overlapped; + caen::uint_t::fast _timestamp; + caen::uint_t::fast _ch_mask; + caen::vector::least>> _waveforms; + std::size_t _event_size; + // software fields + bool _fake_stop_event; + // consistency assertions + static_assert(std::is_same::value, "documented to be handled as std::uint16_t"); + }; + + struct endpoint_impl; // forward declaration + std::unique_ptr _pimpl; + +}; + +using namespace std::string_literals; + +NLOHMANN_JSON_SERIALIZE_ENUM(scope::names, { + { scope::names::UNKNOWN, nullptr }, + { scope::names::TIMESTAMP, "TIMESTAMP"s }, + { scope::names::TIMESTAMP_NS, "TIMESTAMP_NS"s }, + { scope::names::TRIGGER_ID, "TRIGGER_ID"s }, + { scope::names::WAVEFORM, "WAVEFORM"s }, + { scope::names::WAVEFORM_SIZE, "WAVEFORM_SIZE"s }, + { scope::names::FLAGS, "FLAGS"s }, + { scope::names::SAMPLES_OVERLAPPED, "SAMPLES_OVERLAPPED"s }, + { scope::names::BOARD_FAIL, "BOARD_FAIL"s }, + { scope::names::EVENT_SIZE, "EVENT_SIZE"s }, +}) + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_SCOPE_HPP_ */ diff --git a/include/endpoints/sw_endpoint.hpp b/include/endpoints/sw_endpoint.hpp new file mode 100644 index 0000000..ecef7a1 --- /dev/null +++ b/include/endpoints/sw_endpoint.hpp @@ -0,0 +1,118 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file sw_endpoint.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_ENDPOINTS_SW_ENDPOINT_HPP_ +#define CAEN_INCLUDE_ENDPOINTS_SW_ENDPOINT_HPP_ + +#include +#include + +#include "cpp-utility/bit.hpp" +#include "cpp-utility/byte.hpp" +#include "cpp-utility/integer.hpp" +#include "endpoints/endpoint.hpp" + +namespace caen { + +namespace dig2 { + +namespace ep { + +struct sw_endpoint : public endpoint { + + sw_endpoint(client& client, handle::internal_handle_t endpoint_handle); + ~sw_endpoint(); + + virtual void resize() = 0; + virtual void decode(const caen::byte* p, std::size_t size) = 0; + virtual void stop() = 0; + +protected: + // common stuff used to decode + using word_t = std::uint64_t; + using half_word_t = std::uint32_t; + static constexpr std::size_t word_size{sizeof(word_t)}; // in bytes + static constexpr std::size_t half_word_size{sizeof(half_word_t)}; // in bytes + static constexpr std::size_t word_bit_size{caen::bit::bit_size::value}; // in bit + static constexpr std::size_t half_word_bit_size{caen::bit::bit_size::value}; // in bit + static constexpr unsigned int sampling_period_log2{3}; // ns + static constexpr unsigned int sampling_period{1U << sampling_period_log2}; // ns + + struct evt_header { + struct s { + static constexpr std::size_t format{4}; + static constexpr std::size_t implementation_defined{28}; + static constexpr std::size_t n_words{32}; + static_assert(format + implementation_defined + n_words == word_bit_size, "invalid sizes"); + }; + enum struct format : caen::uint_t::fast { + unused = 0b0000, + common_trigger_mode = 0b0001, + individual_trigger_mode = 0b0010, + special_event = 0b0011, + special_time_event = 0b0100, + }; + format _format; + // - implementation_defined not saved into event + caen::uint_t::fast _n_words; + }; + + template + struct timestamp_to_ns { + using type = typename caen::uint_t::fast; + constexpr type operator()(type v) const noexcept { return v * sampling_period; } + }; + + // decode thread needs to decode event header + friend struct raw; + friend struct rawudp; + + bool is_decode_disabled(); + +private: + + struct endpoint_impl; // forward declaration + std::unique_ptr _pimpl; + +}; + +} // namespace ep + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_ENDPOINTS_SW_ENDPOINT_HPP_ */ diff --git a/include/global.hpp b/include/global.hpp new file mode 100644 index 0000000..17ad07b --- /dev/null +++ b/include/global.hpp @@ -0,0 +1,97 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file global.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_GLOBAL_HPP_ +#define CAEN_INCLUDE_GLOBAL_HPP_ + +#include +#include +#include + +#include + +#include "lib_definitions.hpp" +#include "client.hpp" + +namespace caen { + +namespace dig2 { + +struct global : private boost::noncopyable { + + using client_array_type = std::array, max_size::devices>; + + // singleton + static global& get_instance() { + static global instance; + return instance; + } + + template + void create_client(std::size_t board, Args&& ...args) { + _clients[board] = std::make_unique(std::forward(args)...); + } + + void destroy_client(std::size_t board) noexcept { + _clients[board] = nullptr; + } + + bool is_used(std::size_t board) const noexcept { + return _clients[board] != nullptr; + } + + auto& get_client(std::size_t board) const noexcept { + return _clients[board]; + } + + const auto& get_clients() const noexcept { + return _clients; + } + +private: + + global() = default; + ~global() = default; + + client_array_type _clients; + +}; + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_GLOBAL_HPP_ */ diff --git a/include/handle.hpp b/include/handle.hpp new file mode 100644 index 0000000..27327d4 --- /dev/null +++ b/include/handle.hpp @@ -0,0 +1,175 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file handle.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_HANDLE_HPP_ +#define CAEN_INCLUDE_HANDLE_HPP_ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cpp-utility/bit.hpp" +#include "cpp-utility/integer.hpp" +#include "global.hpp" +#include "lib_definitions.hpp" +#include "lib_error.hpp" + +namespace caen { + +namespace dig2 { + +namespace handle { + +struct lib { + + using board_t = caen::uint_t::fast; + +private: + + static constexpr auto client_array_size = std::tuple_size::value; + + // compile time error if max BoardT is smaller than array size (no check_board_index is defined in that case) + + // no range check if handle::board_t stores exactly only valid array indexes + template ::max() == client_array_size - 1), int> = 0> + static constexpr void check_board_index(BoardT) noexcept { + } + + // range check if handle::board_t can store values bigger than array size + template ::max() > client_array_size - 1), int> = 0> + static constexpr void check_board_index(BoardT board) { +#if BOOST_PREDEF_WORKAROUND(BOOST_COMP_GNUC, <, 9, 1, 0) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" // invalid warning with GCC 8, fixed in GCC 9 +#endif + if (BOOST_UNLIKELY(board >= client_array_size)) + throw ex::invalid_argument("invalid board"); +#if BOOST_PREDEF_WORKAROUND(BOOST_COMP_GNUC, <, 9, 1, 0) +#pragma GCC diagnostic pop +#endif + } + + const board_t _board; + const internal_handle_t _internal_handle; + +public: + + static lib get(client_handle_t h) try { + return lib(h); + } + catch (const ex::invalid_argument&) { + throw ex::invalid_handle(h); + } + + static lib get_if_used(client_handle_t h) { + auto ret = get(h); + if (!ret.is_used()) + throw ex::invalid_handle(h); + return ret; + } + + constexpr lib(board_t board, internal_handle_t internal_handle) noexcept(noexcept(check_board_index(_board))) + : _board{board} + , _internal_handle{internal_handle} { + check_board_index(_board); + } + + constexpr explicit lib(client_handle_t h) noexcept(noexcept(check_board_index(_board))) + : lib(get_board_handle(h), get_server_handle(h)) {} + + client& get_client() const { + if (!is_used()) + throw "unused board"_ex; + return *global::get_instance().get_client(_board); + } + + constexpr client_handle_t client_handle() const noexcept { + return static_cast(_internal_handle) | (static_cast(_board) << server_handle_bits); + } + + constexpr board_t board() const noexcept { return _board; } + constexpr internal_handle_t internal_handle() const noexcept { return _internal_handle; } + +private: + + bool is_used() const noexcept { + return global::get_instance().is_used(_board); + } + + static constexpr board_t get_board_handle(client_handle_t h) noexcept { + return caen::bit::mask_at(h); + } + + static constexpr internal_handle_t get_server_handle(client_handle_t h) noexcept { + return caen::bit::mask_at(h); + } + +}; + +namespace sanity_checks { + +constexpr bool test_handle() noexcept { + bool ret{true}; + ret &= (lib(0, 0).client_handle() == client_handle_t{0x00000000}); + ret &= (lib(0, 1).client_handle() == client_handle_t{0x00000001}); + ret &= (lib(1, 0).client_handle() == client_handle_t{0x01000000}); + ret &= (lib(1, 1).client_handle() == client_handle_t{0x01000001}); + ret &= (lib(0xFF, 0xF0F0F0).client_handle() == client_handle_t{0xFFF0F0F0}); + ret &= (lib(0xFFF0F0F0).client_handle() == client_handle_t{0xFFF0F0F0}); + ret &= (lib(0xFFF0F0F0).board() == lib::board_t{0xFF}); + ret &= (lib(0xFFF0F0F0).internal_handle() == internal_handle_t{0xF0F0F0}); + return ret; +} + +BOOST_STATIC_ASSERT(test_handle()); + +} // namespace sanity_checks + +} // namespace handle + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_HANDLE_HPP_ */ diff --git a/include/json/json_data_format.hpp b/include/json/json_data_format.hpp new file mode 100644 index 0000000..6ab7302 --- /dev/null +++ b/include/json/json_data_format.hpp @@ -0,0 +1,120 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file json_data_format.hpp +* \brief +* \author Giovanni Cerretani +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_JSON_JSON_DATA_FORMAT_HPP_ +#define CAEN_INCLUDE_JSON_JSON_DATA_FORMAT_HPP_ + +#include + +#include + +#include + +#include "endpoints/endpoint.hpp" + +namespace caen { + +namespace dig2 { + +using namespace caen::literals; + +template +struct json_data_format { + + /** + * Default constructor needed by nlohmann's JSON. + */ + json_data_format() + : _name{names_type::UNKNOWN} + , _type{types_type::UNKNOWN} + , _dim{} { + } + + /** + * Convert JSON to json_data_format + * @param args any input of nlohmann::json::parse representing a JSON + * @return an instance of json_cmd parsing the input content + */ + template + static json_data_format marshal(Args&& ...args) { + return nlohmann::json::parse(std::forward(args)...).template get(); + } + + /** + * Convert json_data_format to JSON + * @return the JSON with no indentation + */ + nlohmann::json::string_t unmarshal() const { + return nlohmann::json(*this).dump(); + } + + auto get_name() const noexcept { return _name; } + auto get_type() const noexcept { return _type; } + auto get_dim() const noexcept { return _dim; } + + static constexpr auto& key_name() noexcept { return "name"; } + static constexpr auto& key_type() noexcept { return "type"; } + static constexpr auto& key_dim() noexcept { return "dim"; } + + friend void from_json(const nlohmann::json& j, json_data_format& e) { + caen::json::get_if_not_null(j, key_name(), e._name); + caen::json::get_if_not_null(j, key_type(), e._type); + caen::json::get_if_not_null(j, key_dim(), e._dim); + } + + friend void to_json(nlohmann::json& j, const json_data_format& e) { + caen::json::set(j, key_name(), e._name); + caen::json::set(j, key_type(), e._type); + caen::json::set(j, key_dim(), e._dim); + } + +private: + + using traits = ep::utility::endpoint_traits; + using names_type = typename traits::names_type; + using types_type = typename traits::types_type; + + names_type _name; + types_type _type; + std::size_t _dim; + +}; + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_JSON_JSON_DATA_FORMAT_HPP_ */ diff --git a/include/last_error.hpp b/include/last_error.hpp new file mode 100644 index 0000000..d01dcd8 --- /dev/null +++ b/include/last_error.hpp @@ -0,0 +1,65 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file last_error.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_LAST_ERROR_HPP_ +#define CAEN_INCLUDE_LAST_ERROR_HPP_ + +#include + +#include + +#include "cpp-utility/string_view.hpp" + +namespace caen { + +namespace dig2 { + +namespace last_error { + +std::string& instance() noexcept(noexcept(std::string())); + +int _handle_exception(caen::string_view func) noexcept; + +} // namespace last_error + +} // namespace dig2 + +} // namespace caen + +// macro to automatic put function name +#define handle_exception() ::caen::dig2::last_error::_handle_exception(BOOST_CURRENT_FUNCTION) + +#endif /* CAEN_INCLUDE_LAST_ERROR_HPP_ */ diff --git a/include/lib_definitions.hpp b/include/lib_definitions.hpp new file mode 100644 index 0000000..043c75e --- /dev/null +++ b/include/lib_definitions.hpp @@ -0,0 +1,87 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file lib_definitions.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_LIB_DEFINITIONS_HPP_ +#define CAEN_INCLUDE_LIB_DEFINITIONS_HPP_ + +#include +#include +#include + +#include + +#include "cpp-utility/bit.hpp" +#include "cpp-utility/integer.hpp" + +namespace caen { + +namespace dig2 { + +namespace handle { + +static constexpr std::size_t server_handle_bits{cmd::handle_bits}; // from json_common.hpp + +using client_handle_t = cmd::handle_t; +using internal_handle_t = caen::uint_t::fast; + +static constexpr std::size_t board_bits{caen::bit::bit_size::value - server_handle_bits}; +static constexpr internal_handle_t invalid_server_handle{cmd::max_handle}; + +} // namespace handle + +namespace max_size { + +static constexpr std::size_t devices{1 << handle::board_bits}; + +namespace str { + +static constexpr std::size_t version{16}; +static constexpr std::size_t error_name{32}; +static constexpr std::size_t error_description{256}; +static constexpr std::size_t last_error_description{1024}; +static constexpr std::size_t node_name{32}; +static constexpr std::size_t value{256}; +static constexpr std::size_t path{256}; + +} // namespace str + +} // namespace max_size + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_LIB_DEFINITIONS_HPP_ */ diff --git a/include/lib_error.hpp b/include/lib_error.hpp new file mode 100644 index 0000000..0466d9c --- /dev/null +++ b/include/lib_error.hpp @@ -0,0 +1,127 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file lib_error.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_LIB_ERROR_HPP_ +#define CAEN_INCLUDE_LIB_ERROR_HPP_ + +#include +#include +#include + +#include "lib_definitions.hpp" + +namespace caen { + +namespace dig2 { + +namespace ex { + +using namespace std::string_literals; + +struct runtime_error : public std::runtime_error { + using std::runtime_error::runtime_error; +}; + +struct not_enabled : public std::logic_error { + not_enabled() : logic_error("not enabled"s) {} +}; + +struct timeout : public ex::runtime_error { + timeout() : runtime_error("timeout"s) {} +}; + +struct stop : public ex::runtime_error { + stop() : runtime_error("stop"s) {} +}; + +struct not_yet_implemented : public runtime_error { + using ex::runtime_error::runtime_error; +}; + +struct invalid_argument : public std::invalid_argument { + using std::invalid_argument::invalid_argument; +}; + +struct domain_error : public std::domain_error { + using std::domain_error::domain_error; +}; + +struct invalid_handle : public std::invalid_argument { + explicit invalid_handle(handle::client_handle_t handle) : invalid_argument(std::to_string(handle)), _handle{handle} {} + handle::client_handle_t handle() const noexcept { return _handle; } +private: + const handle::client_handle_t _handle; +}; + +struct command_error : public ex::runtime_error { + using ex::runtime_error::runtime_error; +}; + +struct communication_error : public ex::runtime_error { + using ex::runtime_error::runtime_error; +}; + +struct device_not_found : public ex::runtime_error { + using ex::runtime_error::runtime_error; +}; + +struct too_many_devices : public ex::runtime_error { + using ex::runtime_error::runtime_error; +}; + +struct bad_library_version : public ex::runtime_error { + using ex::runtime_error::runtime_error; +}; + +} // namespace ex + +/** + * @brief UDL to generate ex::runtime_error with compile-time defined message. + * + * Example: + * @code + * throw "generic error"_ex; + * @endcode + */ +inline auto operator""_ex(const char* str, std::size_t len) { + return ex::runtime_error(std::string(str, len)); +} + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_LIB_ERROR_HPP_ */ diff --git a/include/library_logger.hpp b/include/library_logger.hpp new file mode 100644 index 0000000..0c52ec1 --- /dev/null +++ b/include/library_logger.hpp @@ -0,0 +1,80 @@ +/****************************************************************************** +* +* CAEN SpA - Software Division +* Via Vetraia, 11 - 55049 - Viareggio ITALY +* +39 0594 388 398 - www.caen.it +* +******************************************************************************* +* +* Copyright (C) 2020-2023 CAEN SpA +* +* This file is part of the CAEN Dig2 Library. +* +* The CAEN Dig2 Library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* The CAEN Dig2 Library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with the CAEN Dig2 Library; if not, see +* https://www.gnu.org/licenses/. +* +* SPDX-License-Identifier: LGPL-3.0-or-later +* +***************************************************************************//*! +* +* \file library_logger.hpp +* \brief +* \author Giovanni Cerretani, Matteo Fusco +* +******************************************************************************/ + +#ifndef CAEN_INCLUDE_LIBRARY_LOGGER_HPP_ +#define CAEN_INCLUDE_LIBRARY_LOGGER_HPP_ + +#include +#include + +#include +#include // required to print custom objects + +#include "cpp-utility/optional.hpp" + +namespace caen { + +namespace dig2 { + +namespace library_logger { + +/** + * Initialize the logger stuff and print version of included libraries on the main sink + */ +void init(); + +/** + * Create a new logger to print on the main sink + * @param name the logger name + * @return a new logger instance + */ +std::shared_ptr create_logger(const std::string& name); + +/** + * Create a new logger to print on the main sink with custom optional level + * @param name the logger name + * @param level optional logger level to override default level + * @return a new logger instance + */ +std::shared_ptr create_logger(const std::string& name, const caen::optional& level); + +} // namespace library_logger + +} // namespace dig2 + +} // namespace caen + +#endif /* CAEN_INCLUDE_LIBRARY_LOGGER_HPP_ */ diff --git a/install-sh b/install-sh new file mode 100644 index 0000000..8175c64 --- /dev/null +++ b/install-sh @@ -0,0 +1,518 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2018-03-11.20; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +tab=' ' +nl=' +' +IFS=" $tab$nl" + +# Set DOITPROG to "echo" to test this script. + +doit=${DOITPROG-} +doit_exec=${doit:-exec} + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +is_target_a_directory=possibly + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) is_target_a_directory=never;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename. + if test -d "$dst"; then + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac + dstdir_status=0 + else + dstdir=`dirname "$dst"` + test -d "$dstdir" + dstdir_status=$? + fi + fi + + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + # Note that $RANDOM variable is not portable (e.g. dash); Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p' feature. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + oIFS=$IFS + IFS=/ + set -f + set fnord $dstdir + shift + set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + set +f && + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/json/LICENSE.MIT b/json/LICENSE.MIT new file mode 100644 index 0000000..1c1f7a6 --- /dev/null +++ b/json/LICENSE.MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2013-2022 Niels Lohmann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/json/README.md b/json/README.md new file mode 100644 index 0000000..9109027 --- /dev/null +++ b/json/README.md @@ -0,0 +1,1891 @@ +[![JSON for Modern C++](docs/json.gif)](https://github.com/nlohmann/json/releases) + +[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json) +[![Ubuntu](https://github.com/nlohmann/json/workflows/Ubuntu/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AUbuntu) +[![macOS](https://github.com/nlohmann/json/workflows/macOS/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AmacOS) +[![Windows](https://github.com/nlohmann/json/workflows/Windows/badge.svg)](https://github.com/nlohmann/json/actions?query=workflow%3AWindows) +[![Coverage Status](https://coveralls.io/repos/github/nlohmann/json/badge.svg?branch=develop)](https://coveralls.io/github/nlohmann/json?branch=develop) +[![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/e0d1a9d5d6fd46fcb655c4cb930bb3e8)](https://www.codacy.com/gh/nlohmann/json/dashboard?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade) +[![Cirrus CI](https://api.cirrus-ci.com/github/nlohmann/json.svg)](https://cirrus-ci.com/github/nlohmann/json) +[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/json.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:json) +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/1mp10JbaANo6FUc7) +[![Documentation](https://img.shields.io/badge/docs-mkdocs-blue.svg)](https://json.nlohmann.me) +[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) +[![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) +[![Vcpkg Version](https://img.shields.io/vcpkg/v/nlohmann-json)](https://vcpkg.link/ports/nlohmann-json) +[![Packaging status](https://repology.org/badge/tiny-repos/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) +[![GitHub Downloads](https://img.shields.io/github/downloads/nlohmann/json/total)](https://github.com/nlohmann/json/releases) +[![GitHub Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](https://github.com/nlohmann/json/issues) +[![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/nlohmann/json.svg)](https://isitmaintained.com/project/nlohmann/json "Average time to resolve an issue") +[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/289/badge)](https://bestpractices.coreinfrastructure.org/projects/289) +[![GitHub Sponsors](https://img.shields.io/badge/GitHub-Sponsors-ff69b4)](https://github.com/sponsors/nlohmann) +[![REUSE status](https://api.reuse.software/badge/github.com/nlohmann/json)](https://api.reuse.software/info/github.com/nlohmann/json) +[![Discord](https://img.shields.io/discord/1003743314341793913)](https://discord.gg/6mrGXKvX7y) + +- [Design goals](#design-goals) +- [Sponsors](#sponsors) +- [Support](#support) ([documentation](https://json.nlohmann.me), [FAQ](https://json.nlohmann.me/home/faq/), [discussions](https://github.com/nlohmann/json/discussions), [API](https://json.nlohmann.me/api/basic_json/), [bug issues](https://github.com/nlohmann/json/issues)) +- [Examples](#examples) + - [Read JSON from a file](#read-json-from-a-file) + - [Creating `json` objects from JSON literals](#creating-json-objects-from-json-literals) + - [JSON as first-class data type](#json-as-first-class-data-type) + - [Serialization / Deserialization](#serialization--deserialization) + - [STL-like access](#stl-like-access) + - [Conversion from STL containers](#conversion-from-stl-containers) + - [JSON Pointer and JSON Patch](#json-pointer-and-json-patch) + - [JSON Merge Patch](#json-merge-patch) + - [Implicit conversions](#implicit-conversions) + - [Conversions to/from arbitrary types](#arbitrary-types-conversions) + - [Specializing enum conversion](#specializing-enum-conversion) + - [Binary formats (BSON, CBOR, MessagePack, UBJSON, and BJData)](#binary-formats-bson-cbor-messagepack-ubjson-and-bjdata) +- [Supported compilers](#supported-compilers) +- [Integration](#integration) + - [CMake](#cmake) + - [Package Managers](#package-managers) + - [Pkg-config](#pkg-config) +- [License](#license) +- [Contact](#contact) +- [Thanks](#thanks) +- [Used third-party tools](#used-third-party-tools) +- [Projects using JSON for Modern C++](#projects-using-json-for-modern-c) +- [Notes](#notes) +- [Execute unit tests](#execute-unit-tests) + +## Design goals + +There are myriads of [JSON](https://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals: + +- **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you'll know what I mean. + +- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. + +- **Serious testing**. Our code is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/tests/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](https://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). + +Other aspects were not so important to us: + +- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs. + +- **Speed**. There are certainly [faster JSON libraries](https://github.com/miloyip/nativejson-benchmark#parsing-time) out there. However, if your goal is to speed up your development by adding JSON support with a single header, then this library is the way to go. If you know how to use a `std::vector` or `std::map`, you are already set. + +See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information. + + +## Sponsors + +You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nlohmann). + +### :office: Corporate Sponsor + +[![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Codacy-logo-black.svg/320px-Codacy-logo-black.svg.png)](https://github.com/codacy/About) + +### :label: Named Sponsors + +- [Michael Hartmann](https://github.com/reFX-Mike) +- [Stefan Hagen](https://github.com/sthagen) +- [Steve Sperandeo](https://github.com/homer6) +- [Robert Jefe Lindstädt](https://github.com/eljefedelrodeodeljefe) +- [Steve Wagner](https://github.com/ciroque) +- [Lion Yang](https://github.com/LionNatsu) + +Thanks everyone! + +## Support + +:question: If you have a **question**, please check if it is already answered in the [**FAQ**](https://json.nlohmann.me/home/faq/) or the [**Q&A**](https://github.com/nlohmann/json/discussions/categories/q-a) section. If not, please [**ask a new question**](https://github.com/nlohmann/json/discussions/new) there. + +:books: If you want to **learn more** about how to use the library, check out the rest of the [**README**](#examples), have a look at [**code examples**](https://github.com/nlohmann/json/tree/develop/docs/examples), or browse through the [**help pages**](https://json.nlohmann.me). + +:construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/). + +:bug: If you found a **bug**, please check the [**FAQ**](https://json.nlohmann.me/home/faq/) if it is a known issue or the result of a design decision. Please also have a look at the [**issue list**](https://github.com/nlohmann/json/issues) before you [**create a new issue**](https://github.com/nlohmann/json/issues/new/choose). Please provide as much information as possible to help us understand and reproduce your issue. + +There is also a [**docset**](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for the documentation browsers [Dash](https://kapeli.com/dash), [Velocity](https://velocity.silverlakesoftware.com), and [Zeal](https://zealdocs.org) that contains the full [documentation](https://json.nlohmann.me) as offline resource. + +## Examples + +Here are some examples to give you an idea how to use the class. + +Beside the examples below, you may want to: + +→ Check the [documentation](https://json.nlohmann.me/)\ +→ Browse the [standalone example files](https://github.com/nlohmann/json/tree/develop/docs/examples) + +Every API function (documented in the [API Documentation](https://json.nlohmann.me/api/basic_json/)) has a corresponding standalone example file. For example, the [`emplace()`](https://json.nlohmann.me/api/basic_json/emplace/) function has a matching [emplace.cpp](https://github.com/nlohmann/json/blob/develop/docs/examples/emplace.cpp) example file. + +### Read JSON from a file + +The `json` class provides an API for manipulating a JSON value. To create a `json` object by reading a JSON file: + +```cpp +#include +#include +using json = nlohmann::json; + +// ... + +std::ifstream f("example.json"); +json data = json::parse(f); +``` + +### Creating `json` objects from JSON literals + +Assume you want to create hard-code this literal JSON value in a file, as a `json` object: + +```json +{ + "pi": 3.141, + "happy": true +} +``` + +There are various options: + +```cpp +// Using (raw) string literals and json::parse +json ex1 = json::parse(R"( + { + "pi": 3.141, + "happy": true + } +)"); + +// Using user-defined (raw) string literals +using namespace nlohmann::literals; +json ex2 = R"( + { + "pi": 3.141, + "happy": true + } +)"_json; + +// Using initializer lists +json ex3 = { + {"happy", true}, + {"pi", 3.141}, +}; +``` + +### JSON as first-class data type + +Here are some examples to give you an idea how to use the class. + +Assume you want to create the JSON object + +```json +{ + "pi": 3.141, + "happy": true, + "name": "Niels", + "nothing": null, + "answer": { + "everything": 42 + }, + "list": [1, 0, 2], + "object": { + "currency": "USD", + "value": 42.99 + } +} +``` + +With this library, you could write: + +```cpp +// create an empty structure (null) +json j; + +// add a number that is stored as double (note the implicit conversion of j to an object) +j["pi"] = 3.141; + +// add a Boolean that is stored as bool +j["happy"] = true; + +// add a string that is stored as std::string +j["name"] = "Niels"; + +// add another null object by passing nullptr +j["nothing"] = nullptr; + +// add an object inside the object +j["answer"]["everything"] = 42; + +// add an array that is stored as std::vector (using an initializer list) +j["list"] = { 1, 0, 2 }; + +// add another object (using an initializer list of pairs) +j["object"] = { {"currency", "USD"}, {"value", 42.99} }; + +// instead, you could also write (which looks very similar to the JSON above) +json j2 = { + {"pi", 3.141}, + {"happy", true}, + {"name", "Niels"}, + {"nothing", nullptr}, + {"answer", { + {"everything", 42} + }}, + {"list", {1, 0, 2}}, + {"object", { + {"currency", "USD"}, + {"value", 42.99} + }} +}; +``` + +Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array()`](https://json.nlohmann.me/api/basic_json/array/) and [`json::object()`](https://json.nlohmann.me/api/basic_json/object/) will help: + +```cpp +// a way to express the empty array [] +json empty_array_explicit = json::array(); + +// ways to express the empty object {} +json empty_object_implicit = json({}); +json empty_object_explicit = json::object(); + +// a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]] +json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} }); +``` + +### Serialization / Deserialization + +#### To/from strings + +You can create a JSON value (deserialization) by appending `_json` to a string literal: + +```cpp +// create object from string literal +json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; + +// or even nicer with a raw string literal +auto j2 = R"( + { + "happy": true, + "pi": 3.141 + } +)"_json; +``` + +Note that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string +value. That is, `json j = "{ \"happy\": true, \"pi\": 3.141 }"` would just store the string +`"{ "happy": true, "pi": 3.141 }"` rather than parsing the actual object. + +The string literal should be brought into scope with `using namespace nlohmann::literals;` +(see [`json::parse()`](https://json.nlohmann.me/api/operator_literal_json/)). + +The above example can also be expressed explicitly using [`json::parse()`](https://json.nlohmann.me/api/basic_json/parse/): + +```cpp +// parse explicitly +auto j3 = json::parse(R"({"happy": true, "pi": 3.141})"); +``` + +You can also get a string representation of a JSON value (serialize): + +```cpp +// explicit conversion to string +std::string s = j.dump(); // {"happy":true,"pi":3.141} + +// serialization with pretty printing +// pass in the amount of spaces to indent +std::cout << j.dump(4) << std::endl; +// { +// "happy": true, +// "pi": 3.141 +// } +``` + +Note the difference between serialization and assignment: + +```cpp +// store a string in a JSON value +json j_string = "this is a string"; + +// retrieve the string value +auto cpp_string = j_string.template get(); +// retrieve the string value (alternative when a variable already exists) +std::string cpp_string2; +j_string.get_to(cpp_string2); + +// retrieve the serialized value (explicit JSON serialization) +std::string serialized_string = j_string.dump(); + +// output of original string +std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.template get() << '\n'; +// output of serialized value +std::cout << j_string << " == " << serialized_string << std::endl; +``` + +[`.dump()`](https://json.nlohmann.me/api/basic_json/dump/) returns the originally stored string value. + +Note the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://json.nlohmann.me/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. + +#### To/from streams (e.g. files, string streams) + +You can also use streams to serialize and deserialize: + +```cpp +// deserialize from standard input +json j; +std::cin >> j; + +// serialize to standard output +std::cout << j; + +// the setw manipulator was overloaded to set the indentation for pretty printing +std::cout << std::setw(4) << j << std::endl; +``` + +These operators work for any subclasses of `std::istream` or `std::ostream`. Here is the same example with files: + +```cpp +// read a JSON file +std::ifstream i("file.json"); +json j; +i >> j; + +// write prettified JSON to another file +std::ofstream o("pretty.json"); +o << std::setw(4) << j << std::endl; +``` + +Please note that setting the exception bit for `failbit` is inappropriate for this use case. It will result in program termination due to the `noexcept` specifier in use. + +#### Read from iterator range + +You can also parse JSON from an iterator range; that is, from any container accessible by iterators whose `value_type` is an integral type of 1, 2 or 4 bytes, which will be interpreted as UTF-8, UTF-16 and UTF-32 respectively. For instance, a `std::vector`, or a `std::list`: + +```cpp +std::vector v = {'t', 'r', 'u', 'e'}; +json j = json::parse(v.begin(), v.end()); +``` + +You may leave the iterators for the range [begin, end): + +```cpp +std::vector v = {'t', 'r', 'u', 'e'}; +json j = json::parse(v); +``` + +#### Custom data source + +Since the parse function accepts arbitrary iterator ranges, you can provide your own data sources by implementing the `LegacyInputIterator` concept. + +```cpp +struct MyContainer { + void advance(); + const char& get_current(); +}; + +struct MyIterator { + using difference_type = std::ptrdiff_t; + using value_type = char; + using pointer = const char*; + using reference = const char&; + using iterator_category = std::input_iterator_tag; + + MyIterator& operator++() { + MyContainer.advance(); + return *this; + } + + bool operator!=(const MyIterator& rhs) const { + return rhs.target != target; + } + + reference operator*() const { + return target.get_current(); + } + + MyContainer* target = nullptr; +}; + +MyIterator begin(MyContainer& tgt) { + return MyIterator{&tgt}; +} + +MyIterator end(const MyContainer&) { + return {}; +} + +void foo() { + MyContainer c; + json j = json::parse(c); +} +``` + +#### SAX interface + +The library uses a SAX-like interface with the following functions: + +```cpp +// called when null is parsed +bool null(); + +// called when a boolean is parsed; value is passed +bool boolean(bool val); + +// called when a signed or unsigned integer number is parsed; value is passed +bool number_integer(number_integer_t val); +bool number_unsigned(number_unsigned_t val); + +// called when a floating-point number is parsed; value and original string is passed +bool number_float(number_float_t val, const string_t& s); + +// called when a string is parsed; value is passed and can be safely moved away +bool string(string_t& val); +// called when a binary value is parsed; value is passed and can be safely moved away +bool binary(binary_t& val); + +// called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known) +bool start_object(std::size_t elements); +bool end_object(); +bool start_array(std::size_t elements); +bool end_array(); +// called when an object key is parsed; value is passed and can be safely moved away +bool key(string_t& val); + +// called when a parse error occurs; byte position, the last token, and an exception is passed +bool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex); +``` + +The return value of each function determines whether parsing should proceed. + +To implement your own SAX handler, proceed as follows: + +1. Implement the SAX interface in a class. You can use class `nlohmann::json_sax` as base class, but you can also use any class where the functions described above are implemented and public. +2. Create an object of your SAX interface class, e.g. `my_sax`. +3. Call `bool json::sax_parse(input, &my_sax)`; where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface. + +Note the `sax_parse` function only returns a `bool` indicating the result of the last executed SAX event. It does not return a `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file [`json_sax.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/input/json_sax.hpp). + +### STL-like access + +We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirement. + +```cpp +// create an array using push_back +json j; +j.push_back("foo"); +j.push_back(1); +j.push_back(true); + +// also use emplace_back +j.emplace_back(1.78); + +// iterate the array +for (json::iterator it = j.begin(); it != j.end(); ++it) { + std::cout << *it << '\n'; +} + +// range-based for +for (auto& element : j) { + std::cout << element << '\n'; +} + +// getter/setter +const auto tmp = j[0].template get(); +j[1] = 42; +bool foo = j.at(2); + +// comparison +j == R"(["foo", 1, true, 1.78])"_json; // true + +// other stuff +j.size(); // 4 entries +j.empty(); // false +j.type(); // json::value_t::array +j.clear(); // the array is empty again + +// convenience type checkers +j.is_null(); +j.is_boolean(); +j.is_number(); +j.is_object(); +j.is_array(); +j.is_string(); + +// create an object +json o; +o["foo"] = 23; +o["bar"] = false; +o["baz"] = 3.141; + +// also use emplace +o.emplace("weather", "sunny"); + +// special iterator member functions for objects +for (json::iterator it = o.begin(); it != o.end(); ++it) { + std::cout << it.key() << " : " << it.value() << "\n"; +} + +// the same code as range for +for (auto& el : o.items()) { + std::cout << el.key() << " : " << el.value() << "\n"; +} + +// even easier with structured bindings (C++17) +for (auto& [key, value] : o.items()) { + std::cout << key << " : " << value << "\n"; +} + +// find an entry +if (o.contains("foo")) { + // there is an entry with key "foo" +} + +// or via find and an iterator +if (o.find("foo") != o.end()) { + // there is an entry with key "foo" +} + +// or simpler using count() +int foo_present = o.count("foo"); // 1 +int fob_present = o.count("fob"); // 0 + +// delete an entry +o.erase("foo"); +``` + + +### Conversion from STL containers + +Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON values (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends on how the elements are ordered in the respective STL container. + +```cpp +std::vector c_vector {1, 2, 3, 4}; +json j_vec(c_vector); +// [1, 2, 3, 4] + +std::deque c_deque {1.2, 2.3, 3.4, 5.6}; +json j_deque(c_deque); +// [1.2, 2.3, 3.4, 5.6] + +std::list c_list {true, true, false, true}; +json j_list(c_list); +// [true, true, false, true] + +std::forward_list c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543}; +json j_flist(c_flist); +// [12345678909876, 23456789098765, 34567890987654, 45678909876543] + +std::array c_array {{1, 2, 3, 4}}; +json j_array(c_array); +// [1, 2, 3, 4] + +std::set c_set {"one", "two", "three", "four", "one"}; +json j_set(c_set); // only one entry for "one" is used +// ["four", "one", "three", "two"] + +std::unordered_set c_uset {"one", "two", "three", "four", "one"}; +json j_uset(c_uset); // only one entry for "one" is used +// maybe ["two", "three", "four", "one"] + +std::multiset c_mset {"one", "two", "one", "four"}; +json j_mset(c_mset); // both entries for "one" are used +// maybe ["one", "two", "one", "four"] + +std::unordered_multiset c_umset {"one", "two", "one", "four"}; +json j_umset(c_umset); // both entries for "one" are used +// maybe ["one", "two", "one", "four"] +``` + +Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON values (see examples above) can be used to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container. + +```cpp +std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; +json j_map(c_map); +// {"one": 1, "three": 3, "two": 2 } + +std::unordered_map c_umap { {"one", 1.2}, {"two", 2.3}, {"three", 3.4} }; +json j_umap(c_umap); +// {"one": 1.2, "two": 2.3, "three": 3.4} + +std::multimap c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; +json j_mmap(c_mmap); // only one entry for key "three" is used +// maybe {"one": true, "two": true, "three": true} + +std::unordered_multimap c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; +json j_ummap(c_ummap); // only one entry for key "three" is used +// maybe {"one": true, "two": true, "three": true} +``` + +### JSON Pointer and JSON Patch + +The library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as alternative means to address structured values. On top of this, **JSON Patch** ([RFC 6902](https://tools.ietf.org/html/rfc6902)) allows describing differences between two JSON values - effectively allowing patch and diff operations known from Unix. + +```cpp +// a JSON value +json j_original = R"({ + "baz": ["one", "two", "three"], + "foo": "bar" +})"_json; + +// access members with a JSON pointer (RFC 6901) +j_original["/baz/1"_json_pointer]; +// "two" + +// a JSON patch (RFC 6902) +json j_patch = R"([ + { "op": "replace", "path": "/baz", "value": "boo" }, + { "op": "add", "path": "/hello", "value": ["world"] }, + { "op": "remove", "path": "/foo"} +])"_json; + +// apply the patch +json j_result = j_original.patch(j_patch); +// { +// "baz": "boo", +// "hello": ["world"] +// } + +// calculate a JSON patch from two JSON values +json::diff(j_result, j_original); +// [ +// { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] }, +// { "op": "remove","path": "/hello" }, +// { "op": "add", "path": "/foo", "value": "bar" } +// ] +``` + +### JSON Merge Patch + +The library supports **JSON Merge Patch** ([RFC 7386](https://tools.ietf.org/html/rfc7386)) as a patch format. Instead of using JSON Pointer (see above) to specify values to be manipulated, it describes the changes using a syntax that closely mimics the document being modified. + +```cpp +// a JSON value +json j_document = R"({ + "a": "b", + "c": { + "d": "e", + "f": "g" + } +})"_json; + +// a patch +json j_patch = R"({ + "a":"z", + "c": { + "f": null + } +})"_json; + +// apply the patch +j_document.merge_patch(j_patch); +// { +// "a": "z", +// "c": { +// "d": "e" +// } +// } +``` + +### Implicit conversions + +Supported types can be implicitly converted to JSON values. + +It is recommended to **NOT USE** implicit conversions **FROM** a JSON value. +You can find more details about this recommendation [here](https://www.github.com/nlohmann/json/issues/958). +You can switch off implicit conversions by defining `JSON_USE_IMPLICIT_CONVERSIONS` to `0` before including the `json.hpp` header. When using CMake, you can also achieve this by setting the option `JSON_ImplicitConversions` to `OFF`. + +```cpp +// strings +std::string s1 = "Hello, world!"; +json js = s1; +auto s2 = js.template get(); +// NOT RECOMMENDED +std::string s3 = js; +std::string s4; +s4 = js; + +// Booleans +bool b1 = true; +json jb = b1; +auto b2 = jb.template get(); +// NOT RECOMMENDED +bool b3 = jb; +bool b4; +b4 = jb; + +// numbers +int i = 42; +json jn = i; +auto f = jn.template get(); +// NOT RECOMMENDED +double f2 = jb; +double f3; +f3 = jb; + +// etc. +``` + +Note that `char` types are not automatically converted to JSON strings, but to integer numbers. A conversion to a string must be specified explicitly: + +```cpp +char ch = 'A'; // ASCII value 65 +json j_default = ch; // stores integer number 65 +json j_string = std::string(1, ch); // stores string "A" +``` + +### Arbitrary types conversions + +Every type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines: + +```cpp +namespace ns { + // a simple struct to model a person + struct person { + std::string name; + std::string address; + int age; + }; +} + +ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; + +// convert to JSON: copy each value into the JSON object +json j; +j["name"] = p.name; +j["address"] = p.address; +j["age"] = p.age; + +// ... + +// convert from JSON: copy each value from the JSON object +ns::person p { + j["name"].template get(), + j["address"].template get(), + j["age"].template get() +}; +``` + +It works, but that's quite a lot of boilerplate... Fortunately, there's a better way: + +```cpp +// create a person +ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60}; + +// conversion: person -> json +json j = p; + +std::cout << j << std::endl; +// {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} + +// conversion: json -> person +auto p2 = j.template get(); + +// that's it +assert(p == p2); +``` + +#### Basic usage + +To make this work with one of your types, you only need to provide two functions: + +```cpp +using json = nlohmann::json; + +namespace ns { + void to_json(json& j, const person& p) { + j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}}; + } + + void from_json(const json& j, person& p) { + j.at("name").get_to(p.name); + j.at("address").get_to(p.address); + j.at("age").get_to(p.age); + } +} // namespace ns +``` + +That's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called. +Likewise, when calling `template get()` or `get_to(your_type&)`, the `from_json` method will be called. + +Some important things: + +* Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined). +* Those methods **MUST** be available (e.g., proper headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. +* When using `template get()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) +* In function `from_json`, use function [`at()`](https://json.nlohmann.me/api/basic_json/at/) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. +* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. + +#### Simplify your life with macros + +If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. + +There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object: + +- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside the namespace of the class/struct to create code for. +- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside the class/struct to create code for. This macro can also access private members. + +In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. + +##### Examples + +The `to_json`/`from_json` functions for the `person` struct above can be created with: + +```cpp +namespace ns { + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) +} +``` + +Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed: + +```cpp +namespace ns { + class address { + private: + std::string street; + int housenumber; + int postcode; + + public: + NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode) + }; +} +``` + +#### How do I convert third-party types? + +This requires a bit more advanced technique. But first, let's see how this conversion mechanism works: + +The library uses **JSON Serializers** to convert types to json. +The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl)). + +It is implemented like this (simplified): + +```cpp +template +struct adl_serializer { + static void to_json(json& j, const T& value) { + // calls the "to_json" method in T's namespace + } + + static void from_json(const json& j, T& value) { + // same thing, but with the "from_json" method + } +}; +``` + +This serializer works fine when you have control over the type's namespace. However, what about `boost::optional` or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`... + +To solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example: + +```cpp +// partial specialization (full specialization works too) +namespace nlohmann { + template + struct adl_serializer> { + static void to_json(json& j, const boost::optional& opt) { + if (opt == boost::none) { + j = nullptr; + } else { + j = *opt; // this will call adl_serializer::to_json which will + // find the free function to_json in T's namespace! + } + } + + static void from_json(const json& j, boost::optional& opt) { + if (j.is_null()) { + opt = boost::none; + } else { + opt = j.template get(); // same as above, but with + // adl_serializer::from_json + } + } + }; +} +``` + +#### How can I use `get()` for non-default constructible/non-copyable types? + +There is a way, if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload: + +```cpp +struct move_only_type { + move_only_type() = delete; + move_only_type(int ii): i(ii) {} + move_only_type(const move_only_type&) = delete; + move_only_type(move_only_type&&) = default; + + int i; +}; + +namespace nlohmann { + template <> + struct adl_serializer { + // note: the return type is no longer 'void', and the method only takes + // one argument + static move_only_type from_json(const json& j) { + return {j.template get()}; + } + + // Here's the catch! You must provide a to_json method! Otherwise, you + // will not be able to convert move_only_type to json, since you fully + // specialized adl_serializer on that type + static void to_json(json& j, move_only_type t) { + j = t.i; + } + }; +} +``` + +#### Can I write my own serializer? (Advanced use) + +Yes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/tests/src/unit-udt.cpp) in the test suite, to see a few examples. + +If you write your own serializer, you'll need to do a few things: + +- use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`) +- use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods +- use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL + +Here is an example, without simplifications, that only accepts types with a size <= 32, and uses ADL. + +```cpp +// You should use void as a second template argument +// if you don't need compile-time checks on T +template::type> +struct less_than_32_serializer { + template + static void to_json(BasicJsonType& j, T value) { + // we want to use ADL, and call the correct to_json overload + using nlohmann::to_json; // this method is called by adl_serializer, + // this is where the magic happens + to_json(j, value); + } + + template + static void from_json(const BasicJsonType& j, T& value) { + // same thing here + using nlohmann::from_json; + from_json(j, value); + } +}; +``` + +Be **very** careful when reimplementing your serializer, you can stack overflow if you don't pay attention: + +```cpp +template +struct bad_serializer +{ + template + static void to_json(BasicJsonType& j, const T& value) { + // this calls BasicJsonType::json_serializer::to_json(j, value); + // if BasicJsonType::json_serializer == bad_serializer ... oops! + j = value; + } + + template + static void to_json(const BasicJsonType& j, T& value) { + // this calls BasicJsonType::json_serializer::from_json(j, value); + // if BasicJsonType::json_serializer == bad_serializer ... oops! + value = j.template get(); // oops! + } +}; +``` + +### Specializing enum conversion + +By default, enum values are serialized to JSON as integers. In some cases this could result in undesired behavior. If an enum is modified or re-ordered after data has been serialized to JSON, the later de-serialized JSON data may be undefined or a different enum value than was originally intended. + +It is possible to more precisely specify how a given enum is mapped to and from JSON as shown below: + +```cpp +// example enum type declaration +enum TaskState { + TS_STOPPED, + TS_RUNNING, + TS_COMPLETED, + TS_INVALID=-1, +}; + +// map TaskState values to JSON as strings +NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, { + {TS_INVALID, nullptr}, + {TS_STOPPED, "stopped"}, + {TS_RUNNING, "running"}, + {TS_COMPLETED, "completed"}, +}) +``` + +The `NLOHMANN_JSON_SERIALIZE_ENUM()` macro declares a set of `to_json()` / `from_json()` functions for type `TaskState` while avoiding repetition and boilerplate serialization code. + +**Usage:** + +```cpp +// enum to JSON as string +json j = TS_STOPPED; +assert(j == "stopped"); + +// json string to enum +json j3 = "running"; +assert(j3.template get() == TS_RUNNING); + +// undefined json value to enum (where the first map entry above is the default) +json jPi = 3.14; +assert(jPi.template get() == TS_INVALID ); +``` + +Just as in [Arbitrary Type Conversions](#arbitrary-types-conversions) above, +- `NLOHMANN_JSON_SERIALIZE_ENUM()` MUST be declared in your enum type's namespace (which can be the global namespace), or the library will not be able to locate it, and it will default to integer serialization. +- It MUST be available (e.g., proper headers must be included) everywhere you use the conversions. + +Other Important points: +- When using `template get()`, undefined JSON values will default to the first pair specified in your map. Select this default pair carefully. +- If an enum or JSON value is specified more than once in your map, the first matching occurrence from the top of the map will be returned when converting to or from JSON. + +### Binary formats (BSON, CBOR, MessagePack, UBJSON, and BJData) + +Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [BSON](https://bsonspec.org) (Binary JSON), [CBOR](https://cbor.io) (Concise Binary Object Representation), [MessagePack](https://msgpack.org), [UBJSON](https://ubjson.org) (Universal Binary JSON Specification) and [BJData](https://neurojson.org/bjdata) (Binary JData) to efficiently encode JSON values to byte vectors and to decode such vectors. + +```cpp +// create a JSON value +json j = R"({"compact": true, "schema": 0})"_json; + +// serialize to BSON +std::vector v_bson = json::to_bson(j); + +// 0x1B, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x00, 0x01, 0x10, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +// roundtrip +json j_from_bson = json::from_bson(v_bson); + +// serialize to CBOR +std::vector v_cbor = json::to_cbor(j); + +// 0xA2, 0x67, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xF5, 0x66, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00 + +// roundtrip +json j_from_cbor = json::from_cbor(v_cbor); + +// serialize to MessagePack +std::vector v_msgpack = json::to_msgpack(j); + +// 0x82, 0xA7, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xC3, 0xA6, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00 + +// roundtrip +json j_from_msgpack = json::from_msgpack(v_msgpack); + +// serialize to UBJSON +std::vector v_ubjson = json::to_ubjson(j); + +// 0x7B, 0x69, 0x07, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x54, 0x69, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x69, 0x00, 0x7D + +// roundtrip +json j_from_ubjson = json::from_ubjson(v_ubjson); +``` + +The library also supports binary types from BSON, CBOR (byte strings), and MessagePack (bin, ext, fixext). They are stored by default as `std::vector` to be processed outside the library. + +```cpp +// CBOR byte string with payload 0xCAFE +std::vector v = {0x42, 0xCA, 0xFE}; + +// read value +json j = json::from_cbor(v); + +// the JSON value has type binary +j.is_binary(); // true + +// get reference to stored binary value +auto& binary = j.get_binary(); + +// the binary value has no subtype (CBOR has no binary subtypes) +binary.has_subtype(); // false + +// access std::vector member functions +binary.size(); // 2 +binary[0]; // 0xCA +binary[1]; // 0xFE + +// set subtype to 0x10 +binary.set_subtype(0x10); + +// serialize to MessagePack +auto cbor = json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE +``` + + +## Supported compilers + +Though it's 2023 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: + +- GCC 4.8 - 12.0 (and possibly later) +- Clang 3.4 - 15.0 (and possibly later) +- Apple Clang 9.1 - 13.1 (and possibly later) +- Intel C++ Compiler 17.0.2 (and possibly later) +- Nvidia CUDA Compiler 11.0.221 (and possibly later) +- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) +- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later) +- Microsoft Visual C++ 2019 / Build Tools 16.3.1+1def00d3d (and possibly later) +- Microsoft Visual C++ 2022 / Build Tools 19.30.30709.0 (and possibly later) + +I would be happy to learn about other compilers/versions. + +Please note: + +- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler. +- Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default. + + ``` + APP_STL := c++_shared + NDK_TOOLCHAIN_VERSION := clang3.6 + APP_CPPFLAGS += -frtti -fexceptions + ``` + + The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10. + +- For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod` or `strtof`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](https://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219). + +- Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case. + +The following compilers are currently used in continuous integration at [AppVeyor](https://ci.appveyor.com/project/nlohmann/json), [Cirrus CI](https://cirrus-ci.com/github/nlohmann/json), and [GitHub Actions](https://github.com/nlohmann/json/actions): + +| Compiler | Operating System | CI Provider | +|--------------------------------------------------------------------------------------------------------|--------------------|----------------| +| Apple Clang 11.0.3 (clang-1103.0.32.62); Xcode 11.7 | macOS 11.7.1 | GitHub Actions | +| Apple Clang 12.0.0 (clang-1200.0.32.29); Xcode 12.4 | macOS 11.7.1 | GitHub Actions | +| Apple Clang 12.0.5 (clang-1205.0.22.11); Xcode 12.5.1 | macOS 11.7.1 | GitHub Actions | +| Apple Clang 13.0.0 (clang-1300.0.29.3); Xcode 13.0 | macOS 11.7.1 | GitHub Actions | +| Apple Clang 13.0.0 (clang-1300.0.29.3); Xcode 13.1 | macOS 12.6.1 | GitHub Actions | +| Apple Clang 13.0.0 (clang-1300.0.29.30); Xcode 13.2.1 | macOS 12.6.1 | GitHub Actions | +| Apple Clang 13.1.6 (clang-1316.0.21.2.3); Xcode 13.3.1 | macOS 12.6.1 | GitHub Actions | +| Apple Clang 13.1.6 (clang-1316.0.21.2.5); Xcode 13.4.1 | macOS 12.6.1 | GitHub Actions | +| Apple Clang 14.0.0 (clang-1400.0.29.102); Xcode 14.0 | macOS 12.6.1 | GitHub Actions | +| Apple Clang 14.0.0 (clang-1400.0.29.102); Xcode 14.0.1 | macOS 12.6.1 | GitHub Actions | +| Apple Clang 14.0.0 (clang-1400.0.29.202); Xcode 14.1 | macOS 12.6.1 | GitHub Actions | +| Clang 3.5.2 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 3.6.2 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 3.7.1 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 3.8.1 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 3.9.1 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 4.0.1 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 5.0.2 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 6.0.1 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 7.0.1 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 8.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 9.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 10.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 10.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | +| Clang 11.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | +| Clang 11.0.0 with MSVC-like command-line | Windows-10.0.17763 | GitHub Actions | +| Clang 11.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 12.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 12.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | +| Clang 13.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 13.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | +| Clang 14.0.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 14.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | +| Clang 15.0.0 with GNU-like command-line | Windows-10.0.17763 | GitHub Actions | +| Clang 15.0.4 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Clang 16.0.0 (16.0.0-++20221031071727+500876226c60-1~exp1~20221031071831.439) | Ubuntu 20.04.3 LTS | GitHub Actions | +| GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu2) | Ubuntu 20.04.3 LTS | GitHub Actions | +| GCC 4.9.4 | Ubuntu 20.04.3 LTS | GitHub Actions | +| GCC 5.5.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| GCC 6.5.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| GCC 7.5.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| GCC 8.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project) | Windows-10.0.17763 | GitHub Actions | +| GCC 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) | Windows-10.0.17763 | GitHub Actions | +| GCC 8.5.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| GCC 9.5.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| GCC 10.4.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| GCC 11.1.0 | Ubuntu (aarch64) | Cirrus CI | +| GCC 11.3.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| GCC 12.2.0 | Ubuntu 20.04.3 LTS | GitHub Actions | +| GCC 13.0.0 20220605 (experimental) | Ubuntu 20.04.3 LTS | GitHub Actions | +| Intel C++ Compiler 2021.5.0.20211109 | Ubuntu 20.04.3 LTS | GitHub Actions | +| NVCC 11.0.221 | Ubuntu 20.04.3 LTS | GitHub Actions | +| Visual Studio 14 2015 MSVC 19.0.24241.7 (Build Engine version 14.0.25420.1) | Windows-6.3.9600 | AppVeyor | +| Visual Studio 15 2017 MSVC 19.16.27035.0 (Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | AppVeyor | +| Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | GitHub Actions | +| Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | AppVeyor | +| Visual Studio 17 2022 MSVC 19.30.30709.0 (Build Engine version 17.0.31804.368 for .NET Framework) | Windows-10.0.20348 | GitHub Actions | + + +## Integration + +[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add + +```cpp +#include + +// for convenience +using json = nlohmann::json; +``` + +to the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang). + +You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`. + +### CMake + +You can also use the `nlohmann_json::nlohmann_json` interface target in CMake. This target populates the appropriate usage requirements for `INTERFACE_INCLUDE_DIRECTORIES` to point to the appropriate include directories and `INTERFACE_COMPILE_FEATURES` for the necessary C++11 flags. + +#### External + +To use this library from a CMake project, you can locate it directly with `find_package()` and use the namespaced imported target from the generated package configuration: + +```cmake +# CMakeLists.txt +find_package(nlohmann_json 3.2.0 REQUIRED) +... +add_library(foo ...) +... +target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) +``` + +The package configuration file, `nlohmann_jsonConfig.cmake`, can be used either from an install tree or directly out of the build tree. + +#### Embedded + +To embed the library directly into an existing CMake project, place the entire source tree in a subdirectory and call `add_subdirectory()` in your `CMakeLists.txt` file: + +```cmake +# Typically you don't care so much for a third party library's tests to be +# run from your own project's code. +set(JSON_BuildTests OFF CACHE INTERNAL "") + +# If you only include this third party in PRIVATE source files, you do not +# need to install it when your main project gets installed. +# set(JSON_Install OFF CACHE INTERNAL "") + +# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it +# unintended consequences that will break the build. It's generally +# discouraged (although not necessarily well documented as such) to use +# include(...) for pulling in other CMake projects anyways. +add_subdirectory(nlohmann_json) +... +add_library(foo ...) +... +target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) +``` + +##### Embedded (FetchContent) + +Since CMake v3.11, +[FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) can +be used to automatically download a release as a dependency at configure time. + +Example: +```cmake +include(FetchContent) + +FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz) +FetchContent_MakeAvailable(json) + +target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) +``` + +**Note**: It is recommended to use the URL approach described above which is supported as of version 3.10.0. See + for more information. + +#### Supporting Both + +To allow your project to support either an externally supplied or an embedded JSON library, you can use a pattern akin to the following: + +``` cmake +# Top level CMakeLists.txt +project(FOO) +... +option(FOO_USE_EXTERNAL_JSON "Use an external JSON library" OFF) +... +add_subdirectory(thirdparty) +... +add_library(foo ...) +... +# Note that the namespaced target will always be available regardless of the +# import method +target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) +``` +```cmake +# thirdparty/CMakeLists.txt +... +if(FOO_USE_EXTERNAL_JSON) + find_package(nlohmann_json 3.2.0 REQUIRED) +else() + set(JSON_BuildTests OFF CACHE INTERNAL "") + add_subdirectory(nlohmann_json) +endif() +... +``` + +`thirdparty/nlohmann_json` is then a complete copy of this source tree. + +### Package Managers + +:beer: If you are using OS X and [Homebrew](https://brew.sh), just type `brew install nlohmann-json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann-json --HEAD`. See [nlohmann-json](https://formulae.brew.sh/formula/nlohmann-json) for more information. + +If you are using the [Meson Build System](https://mesonbuild.com), add this source tree as a [meson subproject](https://mesonbuild.com/Subprojects.html#using-a-subproject). You may also use the `include.zip` published in this project's [Releases](https://github.com/nlohmann/json/releases) to reduce the size of the vendored source tree. Alternatively, you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`. Please see the meson project for any issues regarding the packaging. + +The provided `meson.build` can also be used as an alternative to CMake for installing `nlohmann_json` system-wide in which case a pkg-config file is installed. To use it, simply have your build system require the `nlohmann_json` pkg-config dependency. In Meson, it is preferred to use the [`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than using the subproject directly. + +If you are using [Bazel](https://bazel.build/) you can simply reference this repository using `http_archive` or `git_repository` and depend on `@nlohmann_json//:json`. + +If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add [`nlohmann_json/x.y.z`](https://conan.io/center/nlohmann_json) to your `conanfile`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/conan-io/conan-center-index/issues) if you experience problems with the packages. + +If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the [`nlohmann-json` package](https://spack.readthedocs.io/en/latest/package_list.html#nlohmann-json). Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging. + +If you are using [hunter](https://github.com/cpp-pm/hunter) on your project for external dependencies, then you can use the [nlohmann_json package](https://hunter.readthedocs.io/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging. + +If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. Please file issues [here](https://github.com/buckaroo-pm/nlohmann-json). There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example). + +If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can install the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json) with `vcpkg install nlohmann-json` and follow the then displayed descriptions. Please see the vcpkg project for any issues regarding the packaging. + +If you are using [cget](https://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`). + +If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open). + +If you are using [Swift Package Manager](https://swift.org/package-manager/), you can use the library by adding a package dependency to this repository. And target dependency as `.product(name: "nlohmann-json", package: "json")`. + +If you are using [NuGet](https://www.nuget.org), you can use the package [nlohmann.json](https://www.nuget.org/packages/nlohmann.json/). Please check [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) on how to use the package. Please file issues [here](https://github.com/hnkb/nlohmann-json-nuget/issues). + +If you are using [conda](https://conda.io/), you can use the package [nlohmann_json](https://github.com/conda-forge/nlohmann_json-feedstock) from [conda-forge](https://conda-forge.org) executing `conda install -c conda-forge nlohmann_json`. Please file issues [here](https://github.com/conda-forge/nlohmann_json-feedstock/issues). + +If you are using [MSYS2](https://www.msys2.org/), you can use the [mingw-w64-nlohmann-json](https://packages.msys2.org/base/mingw-w64-nlohmann-json) package, just type `pacman -S mingw-w64-i686-nlohmann-json` or `pacman -S mingw-w64-x86_64-nlohmann-json` for installation. Please file issues [here](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann-json%5D) if you experience problems with the packages. + +If you are using [MacPorts](https://ports.macports.org), execute `sudo port install nlohmann-json` to install the [nlohmann-json](https://ports.macports.org/port/nlohmann-json/) package. + +If you are using [`build2`](https://build2.org), you can use the [`nlohmann-json`](https://cppget.org/nlohmann-json) package from the public repository https://cppget.org or directly from the [package's sources repository](https://github.com/build2-packaging/nlohmann-json). In your project's `manifest` file, just add `depends: nlohmann-json` (probably with some [version constraints](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-add-remove-deps)). If you are not familiar with using dependencies in `build2`, [please read this introduction](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml). +Please file issues [here](https://github.com/build2-packaging/nlohmann-json) if you experience problems with the packages. + +If you are using [`wsjcpp`](https://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch. + +If you are using [`CPM.cmake`](https://github.com/TheLartians/CPM.cmake), you can check this [`example`](https://github.com/TheLartians/CPM.cmake/tree/master/examples/json). After [adding CPM script](https://github.com/TheLartians/CPM.cmake#adding-cpm) to your project, implement the following snippet to your CMake: + +```cmake +CPMAddPackage( + NAME nlohmann_json + GITHUB_REPOSITORY nlohmann/json + VERSION 3.9.1) +``` + +### Pkg-config + +If you are using bare Makefiles, you can use `pkg-config` to generate the include flags that point to where the library is installed: + +```sh +pkg-config nlohmann_json --cflags +``` + +Users of the Meson build system will also be able to use a system-wide library, which will be found by `pkg-config`: + +```meson +json = dependency('nlohmann_json', required: true) +``` + + +## License + + + +The class is licensed under the [MIT License](https://opensource.org/licenses/MIT): + +Copyright © 2013-2022 [Niels Lohmann](https://nlohmann.me) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +* * * + +The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](https://bjoern.hoehrmann.de/) + +The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](https://florian.loitsch.com/) + +The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/). + +The class contains parts of [Google Abseil](https://github.com/abseil/abseil-cpp) which is licensed under the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). + +## Contact + +If you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/nlohmann/json/issues/new/choose). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases. + +Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please use [this key](https://keybase.io/nlohmann/pgp_keys.asc). + +## Security + +[Commits by Niels Lohmann](https://github.com/nlohmann/json/commits) and [releases](https://github.com/nlohmann/json/releases) are signed with this [PGP Key](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69). + +## Thanks + +I deeply appreciate the help of the following people. + + + +1. [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization. +2. [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes. +3. [kirkshoop](https://github.com/kirkshoop) made the iterators of the class composable to other libraries. +4. [wancw](https://github.com/wanwc) fixed a bug that hindered the class to compile with Clang. +5. Tomas Åblad found a bug in the iterator implementation. +6. [Joshua C. Randall](https://github.com/jrandall) fixed a bug in the floating-point serialization. +7. [Aaron Burghardt](https://github.com/aburgh) implemented code to parse streams incrementally. Furthermore, he greatly improved the parser class by allowing the definition of a filter function to discard undesired elements while parsing. +8. [Daniel Kopeček](https://github.com/dkopecek) fixed a bug in the compilation with GCC 5.0. +9. [Florian Weber](https://github.com/Florianjw) fixed a bug in and improved the performance of the comparison operators. +10. [Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping. +11. [易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums. +12. [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio. +13. [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types. +14. [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling. +15. [dariomt](https://github.com/dariomt) fixed some typos in the examples. +16. [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation. +17. [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue. +18. [Huu Nguyen](https://github.com/whoshuu) correct a variable name in the documentation. +19. [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference. +20. [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values. +21. [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. +22. [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. +23. [406345](https://github.com/406345) fixed two small warnings. +24. [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function. +25. [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines. +26. [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers. +27. [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file. +28. [msm-](https://github.com/msm-) added support for American Fuzzy Lop. +29. [Annihil](https://github.com/Annihil) fixed an example in the README file. +30. [Themercee](https://github.com/Themercee) noted a wrong URL in the README file. +31. [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`. +32. [abc100m](https://github.com/abc100m) analyzed the issues with GCC 4.8 and proposed a [partial solution](https://github.com/nlohmann/json/pull/212). +33. [zewt](https://github.com/zewt) added useful notes to the README file about Android. +34. [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake. +35. [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files. +36. [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal). +37. [Mário Feroldi](https://github.com/thelostt) fixed a small typo. +38. [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release. +39. [Damien](https://github.com/dtoma) fixed one of the last conversion warnings. +40. [Thomas Braun](https://github.com/t-b) fixed a warning in a test case and adjusted MSVC calls in the CI. +41. [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types and split the single header file into smaller chunks. +42. [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation. +43. [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`. +44. [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion. +45. [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix. +46. [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file. +47. [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function. +48. [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing. +49. [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan. +50. [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning. +51. [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check. +52. [Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one. +53. [Daniel599](https://github.com/Daniel599) helped to get Travis execute the tests with Clang's sanitizers. +54. [Jonathan Lee](https://github.com/vjon) fixed an example in the README file. +55. [gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types. +56. [Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio. +57. [Jared Grubb](https://github.com/jaredgrubb) supported the implementation of user-defined types. +58. [EnricoBilla](https://github.com/EnricoBilla) noted a typo in an example. +59. [Martin Hořeňovský](https://github.com/horenmar) found a way for a 2x speedup for the compilation time of the test suite. +60. [ukhegg](https://github.com/ukhegg) found proposed an improvement for the examples section. +61. [rswanson-ihi](https://github.com/rswanson-ihi) noted a typo in the README. +62. [Mihai Stan](https://github.com/stanmihai4) fixed a bug in the comparison with `nullptr`s. +63. [Tushar Maheshwari](https://github.com/tusharpm) added [cotire](https://github.com/sakra/cotire) support to speed up the compilation. +64. [TedLyngmo](https://github.com/TedLyngmo) noted a typo in the README, removed unnecessary bit arithmetic, and fixed some `-Weffc++` warnings. +65. [Krzysztof Woś](https://github.com/krzysztofwos) made exceptions more visible. +66. [ftillier](https://github.com/ftillier) fixed a compiler warning. +67. [tinloaf](https://github.com/tinloaf) made sure all pushed warnings are properly popped. +68. [Fytch](https://github.com/Fytch) found a bug in the documentation. +69. [Jay Sistar](https://github.com/Type1J) implemented a Meson build description. +70. [Henry Lee](https://github.com/HenryRLee) fixed a warning in ICC and improved the iterator implementation. +71. [Vincent Thiery](https://github.com/vthiery) maintains a package for the Conan package manager. +72. [Steffen](https://github.com/koemeet) fixed a potential issue with MSVC and `std::min`. +73. [Mike Tzou](https://github.com/Chocobo1) fixed some typos. +74. [amrcode](https://github.com/amrcode) noted a misleading documentation about comparison of floats. +75. [Oleg Endo](https://github.com/olegendo) reduced the memory consumption by replacing `` with ``. +76. [dan-42](https://github.com/dan-42) cleaned up the CMake files to simplify including/reusing of the library. +77. [Nikita Ofitserov](https://github.com/himikof) allowed for moving values from initializer lists. +78. [Greg Hurrell](https://github.com/wincent) fixed a typo. +79. [Dmitry Kukovinets](https://github.com/DmitryKuk) fixed a typo. +80. [kbthomp1](https://github.com/kbthomp1) fixed an issue related to the Intel OSX compiler. +81. [Markus Werle](https://github.com/daixtrose) fixed a typo. +82. [WebProdPP](https://github.com/WebProdPP) fixed a subtle error in a precondition check. +83. [Alex](https://github.com/leha-bot) noted an error in a code sample. +84. [Tom de Geus](https://github.com/tdegeus) reported some warnings with ICC and helped to fix them. +85. [Perry Kundert](https://github.com/pjkundert) simplified reading from input streams. +86. [Sonu Lohani](https://github.com/sonulohani) fixed a small compilation error. +87. [Jamie Seward](https://github.com/jseward) fixed all MSVC warnings. +88. [Nate Vargas](https://github.com/eld00d) added a Doxygen tag file. +89. [pvleuven](https://github.com/pvleuven) helped to fix a warning in ICC. +90. [Pavel](https://github.com/crea7or) helped to fix some warnings in MSVC. +91. [Jamie Seward](https://github.com/jseward) avoided unnecessary string copies in `find()` and `count()`. +92. [Mitja](https://github.com/Itja) fixed some typos. +93. [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links. +94. [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view. +95. [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings. +96. [Eren Okka](https://github.com/erengy) fixed some MSVC warnings. +97. [abolz](https://github.com/abolz) integrated the Grisu2 algorithm for proper floating-point formatting, allowing more roundtrip checks to succeed. +98. [Vadim Evard](https://github.com/Pipeliner) fixed a Markdown issue in the README. +99. [zerodefect](https://github.com/zerodefect) fixed a compiler warning. +100. [Kert](https://github.com/kaidokert) allowed to template the string type in the serialization and added the possibility to override the exceptional behavior. +101. [mark-99](https://github.com/mark-99) helped fixing an ICC error. +102. [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file. +103. [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings. +104. [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager. +105. [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise. +106. [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback. +107. [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type. +108. [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake. +109. [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io). +110. [Carlos O'Ryan](https://github.com/coryan) fixed a typo. +111. [James Upjohn](https://github.com/jammehcow) fixed a version number in the compilers section. +112. [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines and provided documentation for the CMake integration. +113. [Jan Schöppach](https://github.com/dns13) fixed a typo. +114. [martin-mfg](https://github.com/martin-mfg) fixed a typo. +115. [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`. +116. [agrianius](https://github.com/agrianius) added code to use alternative string implementations. +117. [Daniel599](https://github.com/Daniel599) allowed to use more algorithms with the `items()` function. +118. [Julius Rakow](https://github.com/jrakow) fixed the Meson include directory and fixed the links to [cppreference.com](cppreference.com). +119. [Sonu Lohani](https://github.com/sonulohani) fixed the compilation with MSVC 2015 in debug mode. +120. [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases. +121. [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library. +122. [thyu](https://github.com/thyu) fixed a compiler warning. +123. [David Guthrie](https://github.com/LEgregius) fixed a subtle compilation error with Clang 3.4.2. +124. [Dennis Fischer](https://github.com/dennisfischer) allowed to call `find_package` without installing the library. +125. [Hyeon Kim](https://github.com/simnalamburt) fixed an issue with a double macro definition. +126. [Ben Berman](https://github.com/rivertam) made some error messages more understandable. +127. [zakalibit](https://github.com/zakalibit) fixed a compilation problem with the Intel C++ compiler. +128. [mandreyel](https://github.com/mandreyel) fixed a compilation problem. +129. [Kostiantyn Ponomarenko](https://github.com/koponomarenko) added version and license information to the Meson build file. +130. [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8. +131. [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory. +132. [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning. +133. [Dan Gendreau](https://github.com/dgendreau) implemented the `NLOHMANN_JSON_SERIALIZE_ENUM` macro to quickly define an enum/JSON mapping. +134. [efp](https://github.com/efp) added line and column information to parse errors. +135. [julian-becker](https://github.com/julian-becker) added BSON support. +136. [Pratik Chowdhury](https://github.com/pratikpc) added support for structured bindings. +137. [David Avedissian](https://github.com/davedissian) added support for Clang 5.0.1 (PS4 version). +138. [Jonathan Dumaresq](https://github.com/dumarjo) implemented an input adapter to read from `FILE*`. +139. [kjpus](https://github.com/kjpus) fixed a link in the documentation. +140. [Manvendra Singh](https://github.com/manu-chroma) fixed a typo in the documentation. +141. [ziggurat29](https://github.com/ziggurat29) fixed an MSVC warning. +142. [Sylvain Corlay](https://github.com/SylvainCorlay) added code to avoid an issue with MSVC. +143. [mefyl](https://github.com/mefyl) fixed a bug when JSON was parsed from an input stream. +144. [Millian Poquet](https://github.com/mpoquet) allowed to install the library via Meson. +145. [Michael Behrns-Miller](https://github.com/moodboom) found an issue with a missing namespace. +146. [Nasztanovics Ferenc](https://github.com/naszta) fixed a compilation issue with libc 2.12. +147. [Andreas Schwab](https://github.com/andreas-schwab) fixed the endian conversion. +148. [Mark-Dunning](https://github.com/Mark-Dunning) fixed a warning in MSVC. +149. [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) added `operator/` for JSON Pointers. +150. [John-Mark](https://github.com/johnmarkwayve) noted a missing header. +151. [Vitaly Zaitsev](https://github.com/xvitaly) fixed compilation with GCC 9.0. +152. [Laurent Stacul](https://github.com/stac47) fixed compilation with GCC 9.0. +153. [Ivor Wanders](https://github.com/iwanders) helped to reduce the CMake requirement to version 3.1. +154. [njlr](https://github.com/njlr) updated the Buckaroo instructions. +155. [Lion](https://github.com/lieff) fixed a compilation issue with GCC 7 on CentOS. +156. [Isaac Nickaein](https://github.com/nickaein) improved the integer serialization performance and implemented the `contains()` function. +157. [past-due](https://github.com/past-due) suppressed an unfixable warning. +158. [Elvis Oric](https://github.com/elvisoric) improved Meson support. +159. [Matěj Plch](https://github.com/Afforix) fixed an example in the README. +160. [Mark Beckwith](https://github.com/wythe) fixed a typo. +161. [scinart](https://github.com/scinart) fixed bug in the serializer. +162. [Patrick Boettcher](https://github.com/pboettch) implemented `push_back()` and `pop_back()` for JSON Pointers. +163. [Bruno Oliveira](https://github.com/nicoddemus) added support for Conda. +164. [Michele Caini](https://github.com/skypjack) fixed links in the README. +165. [Hani](https://github.com/hnkb) documented how to install the library with NuGet. +166. [Mark Beckwith](https://github.com/wythe) fixed a typo. +167. [yann-morin-1998](https://github.com/yann-morin-1998) helped to reduce the CMake requirement to version 3.1. +168. [Konstantin Podsvirov](https://github.com/podsvirov) maintains a package for the MSYS2 software distro. +169. [remyabel](https://github.com/remyabel) added GNUInstallDirs to the CMake files. +170. [Taylor Howard](https://github.com/taylorhoward92) fixed a unit test. +171. [Gabe Ron](https://github.com/Macr0Nerd) implemented the `to_string` method. +172. [Watal M. Iwasaki](https://github.com/heavywatal) fixed a Clang warning. +173. [Viktor Kirilov](https://github.com/onqtam) switched the unit tests from [Catch](https://github.com/philsquared/Catch) to [doctest](https://github.com/onqtam/doctest) +174. [Juncheng E](https://github.com/ejcjason) fixed a typo. +175. [tete17](https://github.com/tete17) fixed a bug in the `contains` function. +176. [Xav83](https://github.com/Xav83) fixed some cppcheck warnings. +177. [0xflotus](https://github.com/0xflotus) fixed some typos. +178. [Christian Deneke](https://github.com/chris0x44) added a const version of `json_pointer::back`. +179. [Julien Hamaide](https://github.com/crazyjul) made the `items()` function work with custom string types. +180. [Evan Nemerson](https://github.com/nemequ) updated fixed a bug in Hedley and updated this library accordingly. +181. [Florian Pigorsch](https://github.com/flopp) fixed a lot of typos. +182. [Camille Bégué](https://github.com/cbegue) fixed an issue in the conversion from `std::pair` and `std::tuple` to `json`. +183. [Anthony VH](https://github.com/AnthonyVH) fixed a compile error in an enum deserialization. +184. [Yuriy Vountesmery](https://github.com/ua-code-dragon) noted a subtle bug in a preprocessor check. +185. [Chen](https://github.com/dota17) fixed numerous issues in the library. +186. [Antony Kellermann](https://github.com/aokellermann) added a CI step for GCC 10.1. +187. [Alex](https://github.com/gistrec) fixed an MSVC warning. +188. [Rainer](https://github.com/rvjr) proposed an improvement in the floating-point serialization in CBOR. +189. [Francois Chabot](https://github.com/FrancoisChabot) made performance improvements in the input adapters. +190. [Arthur Sonzogni](https://github.com/ArthurSonzogni) documented how the library can be included via `FetchContent`. +191. [Rimas Misevičius](https://github.com/rmisev) fixed an error message. +192. [Alexander Myasnikov](https://github.com/alexandermyasnikov) fixed some examples and a link in the README. +193. [Hubert Chathi](https://github.com/uhoreg) made CMake's version config file architecture-independent. +194. [OmnipotentEntity](https://github.com/OmnipotentEntity) implemented the binary values for CBOR, MessagePack, BSON, and UBJSON. +195. [ArtemSarmini](https://github.com/ArtemSarmini) fixed a compilation issue with GCC 10 and fixed a leak. +196. [Evgenii Sopov](https://github.com/sea-kg) integrated the library to the wsjcpp package manager. +197. [Sergey Linev](https://github.com/linev) fixed a compiler warning. +198. [Miguel Magalhães](https://github.com/magamig) fixed the year in the copyright. +199. [Gareth Sylvester-Bradley](https://github.com/garethsb-sony) fixed a compilation issue with MSVC. +200. [Alexander “weej” Jones](https://github.com/alex-weej) fixed an example in the README. +201. [Antoine Cœur](https://github.com/Coeur) fixed some typos in the documentation. +202. [jothepro](https://github.com/jothepro) updated links to the Hunter package. +203. [Dave Lee](https://github.com/kastiglione) fixed link in the README. +204. [Joël Lamotte](https://github.com/Klaim) added instruction for using Build2's package manager. +205. [Paul Jurczak](https://github.com/pauljurczak) fixed an example in the README. +206. [Sonu Lohani](https://github.com/sonulohani) fixed a warning. +207. [Carlos Gomes Martinho](https://github.com/gocarlos) updated the Conan package source. +208. [Konstantin Podsvirov](https://github.com/podsvirov) fixed the MSYS2 package documentation. +209. [Tridacnid](https://github.com/Tridacnid) improved the CMake tests. +210. [Michael](https://github.com/MBalszun) fixed MSVC warnings. +211. [Quentin Barbarat](https://github.com/quentin-dev) fixed an example in the documentation. +212. [XyFreak](https://github.com/XyFreak) fixed a compiler warning. +213. [TotalCaesar659](https://github.com/TotalCaesar659) fixed links in the README. +214. [Tanuj Garg](https://github.com/tanuj208) improved the fuzzer coverage for UBSAN input. +215. [AODQ](https://github.com/AODQ) fixed a compiler warning. +216. [jwittbrodt](https://github.com/jwittbrodt) made `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` inline. +217. [pfeatherstone](https://github.com/pfeatherstone) improved the upper bound of arguments of the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros. +218. [Jan Procházka](https://github.com/jprochazk) fixed a bug in the CBOR parser for binary and string values. +219. [T0b1-iOS](https://github.com/T0b1-iOS) fixed a bug in the new hash implementation. +220. [Matthew Bauer](https://github.com/matthewbauer) adjusted the CBOR writer to create tags for binary subtypes. +221. [gatopeich](https://github.com/gatopeich) implemented an ordered map container for `nlohmann::ordered_json`. +222. [Érico Nogueira Rolim](https://github.com/ericonr) added support for pkg-config. +223. [KonanM](https://github.com/KonanM) proposed an implementation for the `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`/`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macros. +224. [Guillaume Racicot](https://github.com/gracicot) implemented `string_view` support and allowed C++20 support. +225. [Alex Reinking](https://github.com/alexreinking) improved CMake support for `FetchContent`. +226. [Hannes Domani](https://github.com/ssbssa) provided a GDB pretty printer. +227. Lars Wirzenius reviewed the README file. +228. [Jun Jie](https://github.com/ongjunjie) fixed a compiler path in the CMake scripts. +229. [Ronak Buch](https://github.com/rbuch) fixed typos in the documentation. +230. [Alexander Karzhenkov](https://github.com/karzhenkov) fixed a move constructor and the Travis builds. +231. [Leonardo Lima](https://github.com/leozz37) added CPM.Cmake support. +232. [Joseph Blackman](https://github.com/jbzdarkid) fixed a warning. +233. [Yaroslav](https://github.com/YarikTH) updated doctest and implemented unit tests. +234. [Martin Stump](https://github.com/globberwops) fixed a bug in the CMake files. +235. [Jaakko Moisio](https://github.com/jasujm) fixed a bug in the input adapters. +236. [bl-ue](https://github.com/bl-ue) fixed some Markdown issues in the README file. +237. [William A. Wieselquist](https://github.com/wawiesel) fixed an example from the README. +238. [abbaswasim](https://github.com/abbaswasim) fixed an example from the README. +239. [Remy Jette](https://github.com/remyjette) fixed a warning. +240. [Fraser](https://github.com/frasermarlow) fixed the documentation. +241. [Ben Beasley](https://github.com/musicinmybrain) updated doctest. +242. [Doron Behar](https://github.com/doronbehar) fixed pkg-config.pc. +243. [raduteo](https://github.com/raduteo) fixed a warning. +244. [David Pfahler](https://github.com/theShmoo) added the possibility to compile the library without I/O support. +245. [Morten Fyhn Amundsen](https://github.com/mortenfyhn) fixed a typo. +246. [jpl-mac](https://github.com/jpl-mac) allowed to treat the library as a system header in CMake. +247. [Jason Dsouza](https://github.com/jasmcaus) fixed the indentation of the CMake file. +248. [offa](https://github.com/offa) added a link to Conan Center to the documentation. +249. [TotalCaesar659](https://github.com/TotalCaesar659) updated the links in the documentation to use HTTPS. +250. [Rafail Giavrimis](https://github.com/grafail) fixed the Google Benchmark default branch. +251. [Louis Dionne](https://github.com/ldionne) fixed a conversion operator. +252. [justanotheranonymoususer](https://github.com/justanotheranonymoususer) made the examples in the README more consistent. +253. [Finkman](https://github.com/Finkman) suppressed some `-Wfloat-equal` warnings. +254. [Ferry Huberts](https://github.com/fhuberts) fixed `-Wswitch-enum` warnings. +255. [Arseniy Terekhin](https://github.com/senyai) made the GDB pretty-printer robust against unset variable names. +256. [Amir Masoud Abdol](https://github.com/amirmasoudabdol) updated the Homebrew command as nlohmann/json is now in homebrew-core. +257. [Hallot](https://github.com/Hallot) fixed some `-Wextra-semi-stmt warnings`. +258. [Giovanni Cerretani](https://github.com/gcerretani) fixed `-Wunused` warnings on `JSON_DIAGNOSTICS`. +259. [Bogdan Popescu](https://github.com/Kapeli) hosts the [docset](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B) for offline documentation viewers. +260. [Carl Smedstad](https://github.com/carlsmedstad) fixed an assertion error when using `JSON_DIAGNOSTICS`. +261. [miikka75](https://github.com/miikka75) provided an important fix to compile C++17 code with Clang 9. +262. [Maarten Becker](https://github.com/kernie) fixed a warning for shadowed variables. +263. [Cristi Vîjdea](https://github.com/axnsan12) fixed typos in the `operator[]` documentation. +264. [Alex Beregszaszi](https://github.com/axic) fixed spelling mistakes in comments. +265. [Dirk Stolle](https://github.com/striezel) fixed typos in documentation. +266. [Daniel Albuschat](https://github.com/daniel-kun) corrected the parameter name in the `parse` documentation. +267. [Prince Mendiratta](https://github.com/Prince-Mendiratta) fixed a link to the FAQ. +268. [Florian Albrechtskirchinger](https://github.com/falbrechtskirchinger) implemented `std::string_view` support for object keys and made dozens of other improvements. +269. [Qianqian Fang](https://github.com/fangq) implemented the Binary JData (BJData) format. +270. [pketelsen](https://github.com/pketelsen) added macros `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT` and `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT`. +271. [DarkZeros](https://github.com/DarkZeros) adjusted to code to not clash with Arduino defines. +272. [flagarde](https://github.com/flagarde) fixed the output of `meta()` for MSVC. +273. [Giovanni Cerretani](https://github.com/gcerretani) fixed a check for `std::filesystem`. +274. [Dimitris Apostolou](https://github.com/rex4539) fixed a typo. +275. [Ferry Huberts](https://github.com/fhuberts) fixed a typo. +276. [Michael Nosthoff](https://github.com/heinemml) fixed a typo. +277. [JungHoon Lee](https://github.com/jhnlee) fixed a typo. +278. [Faruk D.](https://github.com/fdiblen) fixed the CITATION.CFF file. +279. [Andrea Cocito](https://github.com/puffetto) added a clarification on macro usage to the documentation. +280. [Krzysiek Karbowiak](https://github.com/kkarbowiak) refactored the tests to use `CHECK_THROWS_WITH_AS`. +281. [Chaoqi Zhang](https://github.com/prncoprs) fixed a typo. +282. [ivanovmp](https://github.com/ivanovmp) fixed a whitespace error. +283. [KsaNL](https://github.com/KsaNL) fixed a build error when including ``. +284. [Andrea Pappacoda](https://github.com/Tachi107) moved `.pc` and `.cmake` files to `share` directory. +285. [Wolf Vollprecht](https://github.com/wolfv) added the `patch_inplace` function. +286. [Jake Zimmerman](https://github.com/jez) highlighted common usage patterns in the README file. +287. [NN](https://github.com/NN---) added the Visual Studio output directory to `.gitignore`. +288. [Romain Reignier](https://github.com/romainreignier) improved the performance the vector output adapter. +289. [Mike](https://github.com/Mike-Leo-Smith) fixed the `std::iterator_traits`. +290. [Richard Hozák](https://github.com/zxey) added macro `JSON_NO_ENUM` to disable default enum conversions. +291. [vakokako](https://github.com/vakokako) fixed tests when compiling with C++20. +292. [Alexander “weej” Jones](https://github.com/alexweej) fixed an example in the README. +293. [Eli Schwartz](https://github.com/eli-schwartz) added more files to the `include.zip` archive. +294. [Kevin Lu](https://github.com/kevinlul) fixed a compilation issue when typedefs with certain names were present. +295. [Trevor Hickey](https://github.com/luxe) improved the description of an example. +296. [Jef LeCompte](https://github.com/jef) updated the year in the README file. +297. [Alexandre Hamez](https://github.com/ahamez) fixed a warning. +298. [Maninderpal Badhan](https://github.com/mbadhan) fixed a typo. +299. [kevin--](https://github.com/kevin--) added a note to an example in the README file. +300. [I](https://github.com/wx257osn2) fixed a typo. +301. [Gregorio Litenstein](https://github.com/Lord-Kamina) fixed the Clang detection. +302. [Andreas Smas](https://github.com/andoma) added a Doozer badge. +303. [WanCW](https://github.com/wancw) fixed the string conversion with Clang. +304. [zhaohuaxishi](https://github.com/zhaohuaxishi) fixed a Doxygen error. +305. [emvivre](https://github.com/emvivre) removed an invalid parameter from CMake. +306. [Tobias Hermann](https://github.com/Dobiasd) fixed a link in the README file. +307. [Michael](https://github.com/traits) fixed a warning. +308. [Ryan Mulder](https://github.com/ryanjmulder) added `ensure_ascii` to the `dump` function. +309. [Muri Nicanor](https://github.com/murinicanor) fixed the `sed` discovery in the Makefile. +310. [David Avedissian](https://github.com/dgavedissian) implemented SFINAE-friendly `iterator_traits`. +311. [AQNOUCH Mohammed](https://github.com/aqnouch) fixed a typo in the README. +312. [Gareth Sylvester-Bradley](https://github.com/garethsb) added `operator/=` and `operator/` to construct JSON pointers. +313. [Michael Macnair](https://github.com/mykter) added support for afl-fuzz testing. +314. [Berkus Decker](https://github.com/berkus) fixed a typo in the README. +315. [Illia Polishchuk](https://github.com/effolkronium) improved the CMake testing. +316. [Ikko Ashimine](https://github.com/eltociear) fixed a typo. +317. [Raphael Grimm](https://github.com/barcode) added the possibility to define a custom base class. +318. [tocic](https://github.com/tocic) fixed typos in the documentation. +319. [Vertexwahn](https://github.com/Vertexwahn) added Bazel build support. +320. [Dirk Stolle](https://github.com/striezel) fixed typos in the documentation. +321. [DavidKorczynski](https://github.com/DavidKorczynski) added a CIFuzz CI GitHub action. +322. [Finkman](https://github.com/Finkman) fixed the debug pretty-printer. +323. [Florian Segginger](https://github.com/floriansegginger) bumped the years in the README. +324. [haadfida](https://github.com/haadfida) cleaned up the badges of used services. +325. [Arsen Arsenović](https://github.com/ArsenArsen) fixed a build error. +326. [theevilone45](https://github.com/theevilone45) fixed a typo in a CMake file. +327. [Sergei Trofimovich](https://github.com/trofi) fixed the custom allocator support. +328. [Joyce](https://github.com/joycebrum) fixed some security issues in the GitHub workflows. +329. [Nicolas Jakob](https://github.com/njakob) add vcpkg version badge. +330. [Tomerkm](https://github.com/Tomerkm) added tests. +331. [No.](https://github.com/tusooa) fixed the use of `get<>` calls. +332. [taro](https://github.com/tarolling) fixed a typo in the `CODEOWNERS` file. +333. [Ikko Eltociear Ashimine](https://github.com/eltociear) fixed a typo. +334. [Felix Yan](https://github.com/felixonmars) fixed a typo in the README. +335. [HO-COOH](https://github.com/HO-COOH) fixed a parentheses in the documentation. +336. [Ivor Wanders](https://github.com/iwanders) fixed the examples to catch exception by `const&`. +337. [miny1233](https://github.com/miny1233) fixed a parentheses in the documentation. +338. [tomalakgeretkal](https://github.com/tomalakgeretkal) fixed a compilation error. +339. [alferov](https://github.com/ALF-ONE) fixed a compilation error. +340. [Craig Scott](https://github.com/craigscott-crascit) fixed a deprecation warning in CMake. +341. [Vyacheslav Zhdanovskiy](https://github.com/ZeronSix) added macros for serialization-only types. +342. [Mathieu Westphal](https://github.com/mwestphal) fixed typos. +343. [scribam](https://github.com/scribam) fixed the MinGW workflow. +344. [Aleksei Sapitskii](https://github.com/aleksproger) added support for Apple's Swift Package Manager. +345. [Benjamin Buch](https://github.com/bebuch) fixed the installation path in CMake. +346. [Colby Haskell](https://github.com/colbychaskell) clarified the parse error message in case a file cannot be opened. + +Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. + + +## Used third-party tools + +The library itself consists of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot! + +- [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file +- [**American fuzzy lop**](https://lcamtuf.coredump.cx/afl/) for fuzz testing +- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows +- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code indentation +- [**Clang**](https://clang.llvm.org) for compilation with code sanitizers +- [**CMake**](https://cmake.org) for build automation +- [**Codacy**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json) +- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json) +- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json) +- [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis +- [**doctest**](https://github.com/onqtam/doctest) for the unit tests +- [**git-update-ghpages**](https://github.com/rstacruz/git-update-ghpages) to upload the documentation to gh-pages +- [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md) +- [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks +- [**Hedley**](https://nemequ.github.io/hedley/) to avoid re-inventing several compiler-agnostic feature macros +- [**lcov**](http://ltp.sourceforge.net/coverage/lcov.php) to process coverage information and create an HTML view +- [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz +- [**Material for MkDocs**](https://squidfunk.github.io/mkdocs-material/) for the style of the documentation site +- [**MkDocs**](https://www.mkdocs.org) for the documentation site +- [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json)) +- [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments. +- [**Valgrind**](https://valgrind.org) to check for correct memory management + + +## Projects using JSON for Modern C++ + +The library is currently used in Apple macOS Sierra-Monterey and iOS 10-15. I am not sure what they are using the library for, but I am happy that it runs on so many devices. + + +## Notes + +### Character encoding + +The library supports **Unicode input** as follows: + +- Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 8259](https://tools.ietf.org/html/rfc8259.html#section-8.1). +- `std::u16string` and `std::u32string` can be parsed, assuming UTF-16 and UTF-32 encoding, respectively. These encodings are not supported when reading from files or other input containers. +- Other encodings such as Latin-1 or ISO 8859-1 are **not** supported and will yield parse or serialization errors. +- [Unicode noncharacters](https://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library. +- Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors. +- The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs. +- When you store strings with different encodings in the library, calling [`dump()`](https://json.nlohmann.me/api/basic_json/dump/) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers. +- To store wide strings (e.g., `std::wstring`), you need to convert them to a UTF-8 encoded `std::string` before, see [an example](https://json.nlohmann.me/home/faq/#wide-string-handling). + +### Comments in JSON + +This library does not support comments by default. It does so for three reasons: + +1. Comments are not part of the [JSON specification](https://tools.ietf.org/html/rfc8259). You may argue that `//` or `/* */` are allowed in JavaScript, but JSON is not JavaScript. +2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012: + + > I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't. + + > Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser. + +3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this. + +However, you can pass set parameter `ignore_comments` to true in the `parse` function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. + +### Order of object keys + +By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". + +If you do want to preserve the insertion order, you can try the type [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179). Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). + +### Memory Release + +We checked with Valgrind and the Address Sanitizer (ASAN) that there are no memory leaks. + +If you find that a parsing program with this library does not release memory, please consider the following case, and it may be unrelated to this library. + +**Your program is compiled with glibc.** There is a tunable threshold that glibc uses to decide whether to actually return memory to the system or whether to cache it for later reuse. If in your program you make lots of small allocations and those small allocations are not a contiguous block and are presumably below the threshold, then they will not get returned to the OS. +Here is a related issue [#1924](https://github.com/nlohmann/json/issues/1924). + +### Further notes + +- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://json.nlohmann.me/api/basic_json/operator%5B%5D/) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://json.nlohmann.me/api/basic_json/at/). Furthermore, you can define `JSON_ASSERT(x)` to replace calls to `assert(x)`. +- As the exact number type is not defined in the [JSON specification](https://tools.ietf.org/html/rfc8259.html), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. +- The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag. +- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. Note the explanatory [`what()`](https://en.cppreference.com/w/cpp/error/exception/what) string of exceptions is not available for MSVC if exceptions are disabled, see [#2824](https://github.com/nlohmann/json/discussions/2824). + +## Execute unit tests + +To compile and run the tests, you need to execute + +```sh +$ mkdir build +$ cd build +$ cmake .. -DJSON_BuildTests=On +$ cmake --build . +$ ctest --output-on-failure +``` + +Note that during the `ctest` stage, several JSON test files are downloaded from an [external repository](https://github.com/nlohmann/json_test_data). If policies forbid downloading artifacts during testing, you can download the files yourself and pass the directory with the test files via `-DJSON_TestDataDirectory=path` to CMake. Then, no Internet connectivity is required. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information. + +If the test suite is not found, several test suites will fail like this: + +``` +=============================================================================== +json/tests/src/make_test_data_available.hpp:21: +TEST CASE: check test suite is downloaded + +json/tests/src/make_test_data_available.hpp:23: FATAL ERROR: REQUIRE( utils::check_testsuite_downloaded() ) is NOT correct! + values: REQUIRE( false ) + logged: Test data not found in 'json/cmake-build-debug/json_test_data'. + Please execute target 'download_test_data' before running this test suite. + See for more information. + +=============================================================================== +``` + +In case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure` will fail. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information. + +Some tests change the installed files and hence make the whole process not reproducible. Please execute `ctest -LE not_reproducible` to skip these tests. See [issue #2324](https://github.com/nlohmann/json/issues/2324) for more information. + +Note you need to call `cmake -LE "not_reproducible|git_required"` to exclude both labels. See [issue #2596](https://github.com/nlohmann/json/issues/2596) for more information. + +As Intel compilers use unsafe floating point optimization by default, the unit tests may fail. Use flag [`/fp:precise`](https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/compiler-options/compiler-option-details/floating-point-options/fp-model-fp.html) then. diff --git a/json/include/nlohmann/adl_serializer.hpp b/json/include/nlohmann/adl_serializer.hpp new file mode 100644 index 0000000..56a606c --- /dev/null +++ b/json/include/nlohmann/adl_serializer.hpp @@ -0,0 +1,55 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +/// @sa https://json.nlohmann.me/api/adl_serializer/ +template +struct adl_serializer +{ + /// @brief convert a JSON value to any value type + /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ + template + static auto from_json(BasicJsonType && j, TargetType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + -> decltype(::nlohmann::from_json(std::forward(j), val), void()) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /// @brief convert a JSON value to any value type + /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ + template + static auto from_json(BasicJsonType && j) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), detail::identity_tag {}))) + -> decltype(::nlohmann::from_json(std::forward(j), detail::identity_tag {})) + { + return ::nlohmann::from_json(std::forward(j), detail::identity_tag {}); + } + + /// @brief convert any value type to a JSON value + /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/ + template + static auto to_json(BasicJsonType& j, TargetType && val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) + { + ::nlohmann::to_json(j, std::forward(val)); + } +}; + +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/byte_container_with_subtype.hpp b/json/include/nlohmann/byte_container_with_subtype.hpp new file mode 100644 index 0000000..91382cd --- /dev/null +++ b/json/include/nlohmann/byte_container_with_subtype.hpp @@ -0,0 +1,103 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // uint8_t, uint64_t +#include // tie +#include // move + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +/// @brief an internal type for a backed binary type +/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/ +template +class byte_container_with_subtype : public BinaryType +{ + public: + using container_type = BinaryType; + using subtype_type = std::uint64_t; + + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ + byte_container_with_subtype() noexcept(noexcept(container_type())) + : container_type() + {} + + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ + byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) + : container_type(b) + {} + + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ + byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + {} + + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ + byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) + : container_type(b) + , m_subtype(subtype_) + , m_has_subtype(true) + {} + + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ + byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + , m_subtype(subtype_) + , m_has_subtype(true) + {} + + bool operator==(const byte_container_with_subtype& rhs) const + { + return std::tie(static_cast(*this), m_subtype, m_has_subtype) == + std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); + } + + bool operator!=(const byte_container_with_subtype& rhs) const + { + return !(rhs == *this); + } + + /// @brief sets the binary subtype + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/ + void set_subtype(subtype_type subtype_) noexcept + { + m_subtype = subtype_; + m_has_subtype = true; + } + + /// @brief return the binary subtype + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/ + constexpr subtype_type subtype() const noexcept + { + return m_has_subtype ? m_subtype : static_cast(-1); + } + + /// @brief return whether the value has a subtype + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/ + constexpr bool has_subtype() const noexcept + { + return m_has_subtype; + } + + /// @brief clears the binary subtype + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/ + void clear_subtype() noexcept + { + m_subtype = 0; + m_has_subtype = false; + } + + private: + subtype_type m_subtype = 0; + bool m_has_subtype = false; +}; + +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/abi_macros.hpp b/json/include/nlohmann/detail/abi_macros.hpp new file mode 100644 index 0000000..f48b9eb --- /dev/null +++ b/json/include/nlohmann/detail/abi_macros.hpp @@ -0,0 +1,100 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +// This file contains all macro definitions affecting or depending on the ABI + +#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 + #warning "Already included a different version of the library!" + #endif + #endif +#endif + +#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + +#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 +#endif + +#if JSON_DIAGNOSTICS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp +#else + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif + +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) + +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + +#ifndef NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ + { +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_END +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann +#endif diff --git a/json/include/nlohmann/detail/conversions/from_json.hpp b/json/include/nlohmann/detail/conversions/from_json.hpp new file mode 100644 index 0000000..aa2f0cb --- /dev/null +++ b/json/include/nlohmann/detail/conversions/from_json.hpp @@ -0,0 +1,497 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +#include +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_null())) + { + JSON_THROW(type_error::create(302, concat("type must be null, but is ", j.type_name()), &j)); + } + n = nullptr; +} + +// overloads for basic_json template parameters +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < std::is_arithmetic::value&& + !std::is_same::value, + int > = 0 > +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + + case value_t::null: + case value_t::object: + case value_t::array: + case value_t::string: + case value_t::boolean: + case value_t::binary: + case value_t::discarded: + default: + JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j)); + } +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) + { + JSON_THROW(type_error::create(302, concat("type must be boolean, but is ", j.type_name()), &j)); + } + b = *j.template get_ptr(); +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); + } + s = *j.template get_ptr(); +} + +template < + typename BasicJsonType, typename StringType, + enable_if_t < + std::is_assignable::value + && is_detected_exact::value + && !std::is_same::value + && !is_json_ref::value, int > = 0 > +inline void from_json(const BasicJsonType& j, StringType& s) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); + } + + s = *j.template get_ptr(); +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +#if !JSON_DISABLE_ENUM_SERIALIZATION +template::value, int> = 0> +inline void from_json(const BasicJsonType& j, EnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} +#endif // JSON_DISABLE_ENUM_SERIALIZATION + +// forward_list doesn't have an insert method +template::value, int> = 0> +inline void from_json(const BasicJsonType& j, std::forward_list& l) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + l.clear(); + std::transform(j.rbegin(), j.rend(), + std::front_inserter(l), [](const BasicJsonType & i) + { + return i.template get(); + }); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +inline void from_json(const BasicJsonType& j, std::valarray& l) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + l.resize(j.size()); + std::transform(j.begin(), j.end(), std::begin(l), + [](const BasicJsonType & elem) + { + return elem.template get(); + }); +} + +template +auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get(), void()) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template +inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) +{ + arr = *j.template get_ptr(); +} + +template +auto from_json_array_impl(const BasicJsonType& j, std::array& arr, + priority_tag<2> /*unused*/) +-> decltype(j.template get(), void()) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template::value, + int> = 0> +auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( + arr.reserve(std::declval()), + j.template get(), + void()) +{ + using std::end; + + ConstructibleArrayType ret; + ret.reserve(j.size()); + std::transform(j.begin(), j.end(), + std::inserter(ret, end(ret)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); + arr = std::move(ret); +} + +template::value, + int> = 0> +inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, + priority_tag<0> /*unused*/) +{ + using std::end; + + ConstructibleArrayType ret; + std::transform( + j.begin(), j.end(), std::inserter(ret, end(ret)), + [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); + arr = std::move(ret); +} + +template < typename BasicJsonType, typename ConstructibleArrayType, + enable_if_t < + is_constructible_array_type::value&& + !is_constructible_object_type::value&& + !is_constructible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > +auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) +-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), +j.template get(), +void()) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + + from_json_array_impl(j, arr, priority_tag<3> {}); +} + +template < typename BasicJsonType, typename T, std::size_t... Idx > +std::array from_json_inplace_array_impl(BasicJsonType&& j, + identity_tag> /*unused*/, index_sequence /*unused*/) +{ + return { { std::forward(j).at(Idx).template get()... } }; +} + +template < typename BasicJsonType, typename T, std::size_t N > +auto from_json(BasicJsonType&& j, identity_tag> tag) +-> decltype(from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {})) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + + return from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {}); +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) + { + JSON_THROW(type_error::create(302, concat("type must be binary, but is ", j.type_name()), &j)); + } + + bin = *j.template get_ptr(); +} + +template::value, int> = 0> +inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_object())) + { + JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j)); + } + + ConstructibleObjectType ret; + const auto* inner_object = j.template get_ptr(); + using value_type = typename ConstructibleObjectType::value_type; + std::transform( + inner_object->begin(), inner_object->end(), + std::inserter(ret, ret.begin()), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type(p.first, p.second.template get()); + }); + obj = std::move(ret); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < + std::is_arithmetic::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value, + int > = 0 > +inline void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + + case value_t::null: + case value_t::object: + case value_t::array: + case value_t::string: + case value_t::binary: + case value_t::discarded: + default: + JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j)); + } +} + +template +std::tuple from_json_tuple_impl_base(BasicJsonType&& j, index_sequence /*unused*/) +{ + return std::make_tuple(std::forward(j).at(Idx).template get()...); +} + +template < typename BasicJsonType, class A1, class A2 > +std::pair from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<0> /*unused*/) +{ + return {std::forward(j).at(0).template get(), + std::forward(j).at(1).template get()}; +} + +template +inline void from_json_tuple_impl(BasicJsonType&& j, std::pair& p, priority_tag<1> /*unused*/) +{ + p = from_json_tuple_impl(std::forward(j), identity_tag> {}, priority_tag<0> {}); +} + +template +std::tuple from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<2> /*unused*/) +{ + return from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); +} + +template +inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple& t, priority_tag<3> /*unused*/) +{ + t = from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); +} + +template +auto from_json(BasicJsonType&& j, TupleRelated&& t) +-> decltype(from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {})) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + + return from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {}); +} + +template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +inline void from_json(const BasicJsonType& j, std::map& m) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + m.clear(); + for (const auto& p : j) + { + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j)); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +inline void from_json(const BasicJsonType& j, std::unordered_map& m) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + m.clear(); + for (const auto& p : j) + { + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j)); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM +template +inline void from_json(const BasicJsonType& j, std_fs::path& p) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); + } + p = *j.template get_ptr(); +} +#endif + +struct from_json_fn +{ + template + auto operator()(const BasicJsonType& j, T&& val) const + noexcept(noexcept(from_json(j, std::forward(val)))) + -> decltype(from_json(j, std::forward(val))) + { + return from_json(j, std::forward(val)); + } +}; + +} // namespace detail + +#ifndef JSON_HAS_CPP_17 +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) +{ +#endif +JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers) + detail::static_const::value; +#ifndef JSON_HAS_CPP_17 +} // namespace +#endif + +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/conversions/to_chars.hpp b/json/include/nlohmann/detail/conversions/to_chars.hpp new file mode 100644 index 0000000..e10741c --- /dev/null +++ b/json/include/nlohmann/detail/conversions/to_chars.hpp @@ -0,0 +1,1118 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2009 Florian Loitsch +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // array +#include // signbit, isfinite +#include // intN_t, uintN_t +#include // memcpy, memmove +#include // numeric_limits +#include // conditional + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief implements the Grisu2 algorithm for binary to decimal floating-point +conversion. + +This implementation is a slightly modified version of the reference +implementation which may be obtained from +http://florian.loitsch.com/publications (bench.tar.gz). + +The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. + +For a detailed description of the algorithm see: + +[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with + Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming + Language Design and Implementation, PLDI 2010 +[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", + Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language + Design and Implementation, PLDI 1996 +*/ +namespace dtoa_impl +{ + +template +Target reinterpret_bits(const Source source) +{ + static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); + + Target target; + std::memcpy(&target, &source, sizeof(Source)); + return target; +} + +struct diyfp // f * 2^e +{ + static constexpr int kPrecision = 64; // = q + + std::uint64_t f = 0; + int e = 0; + + constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {} + + /*! + @brief returns x - y + @pre x.e == y.e and x.f >= y.f + */ + static diyfp sub(const diyfp& x, const diyfp& y) noexcept + { + JSON_ASSERT(x.e == y.e); + JSON_ASSERT(x.f >= y.f); + + return {x.f - y.f, x.e}; + } + + /*! + @brief returns x * y + @note The result is rounded. (Only the upper q bits are returned.) + */ + static diyfp mul(const diyfp& x, const diyfp& y) noexcept + { + static_assert(kPrecision == 64, "internal error"); + + // Computes: + // f = round((x.f * y.f) / 2^q) + // e = x.e + y.e + q + + // Emulate the 64-bit * 64-bit multiplication: + // + // p = u * v + // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) + // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) + // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) + // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) + // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) + // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) + // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) + // + // (Since Q might be larger than 2^32 - 1) + // + // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) + // + // (Q_hi + H does not overflow a 64-bit int) + // + // = p_lo + 2^64 p_hi + + const std::uint64_t u_lo = x.f & 0xFFFFFFFFu; + const std::uint64_t u_hi = x.f >> 32u; + const std::uint64_t v_lo = y.f & 0xFFFFFFFFu; + const std::uint64_t v_hi = y.f >> 32u; + + const std::uint64_t p0 = u_lo * v_lo; + const std::uint64_t p1 = u_lo * v_hi; + const std::uint64_t p2 = u_hi * v_lo; + const std::uint64_t p3 = u_hi * v_hi; + + const std::uint64_t p0_hi = p0 >> 32u; + const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu; + const std::uint64_t p1_hi = p1 >> 32u; + const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu; + const std::uint64_t p2_hi = p2 >> 32u; + + std::uint64_t Q = p0_hi + p1_lo + p2_lo; + + // The full product might now be computed as + // + // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) + // p_lo = p0_lo + (Q << 32) + // + // But in this particular case here, the full p_lo is not required. + // Effectively we only need to add the highest bit in p_lo to p_hi (and + // Q_hi + 1 does not overflow). + + Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up + + const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u); + + return {h, x.e + y.e + 64}; + } + + /*! + @brief normalize x such that the significand is >= 2^(q-1) + @pre x.f != 0 + */ + static diyfp normalize(diyfp x) noexcept + { + JSON_ASSERT(x.f != 0); + + while ((x.f >> 63u) == 0) + { + x.f <<= 1u; + x.e--; + } + + return x; + } + + /*! + @brief normalize x such that the result has the exponent E + @pre e >= x.e and the upper e - x.e bits of x.f must be zero. + */ + static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept + { + const int delta = x.e - target_exponent; + + JSON_ASSERT(delta >= 0); + JSON_ASSERT(((x.f << delta) >> delta) == x.f); + + return {x.f << delta, target_exponent}; + } +}; + +struct boundaries +{ + diyfp w; + diyfp minus; + diyfp plus; +}; + +/*! +Compute the (normalized) diyfp representing the input number 'value' and its +boundaries. + +@pre value must be finite and positive +*/ +template +boundaries compute_boundaries(FloatType value) +{ + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // Convert the IEEE representation into a diyfp. + // + // If v is denormal: + // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) + // If v is normalized: + // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) + + static_assert(std::numeric_limits::is_iec559, + "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); + + constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) + constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); + constexpr int kMinExp = 1 - kBias; + constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) + + using bits_type = typename std::conditional::type; + + const auto bits = static_cast(reinterpret_bits(value)); + const std::uint64_t E = bits >> (kPrecision - 1); + const std::uint64_t F = bits & (kHiddenBit - 1); + + const bool is_denormal = E == 0; + const diyfp v = is_denormal + ? diyfp(F, kMinExp) + : diyfp(F + kHiddenBit, static_cast(E) - kBias); + + // Compute the boundaries m- and m+ of the floating-point value + // v = f * 2^e. + // + // Determine v- and v+, the floating-point predecessor and successor if v, + // respectively. + // + // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) + // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) + // + // v+ = v + 2^e + // + // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ + // between m- and m+ round to v, regardless of how the input rounding + // algorithm breaks ties. + // + // ---+-------------+-------------+-------------+-------------+--- (A) + // v- m- v m+ v+ + // + // -----------------+------+------+-------------+-------------+--- (B) + // v- m- v m+ v+ + + const bool lower_boundary_is_closer = F == 0 && E > 1; + const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); + const diyfp m_minus = lower_boundary_is_closer + ? diyfp(4 * v.f - 1, v.e - 2) // (B) + : diyfp(2 * v.f - 1, v.e - 1); // (A) + + // Determine the normalized w+ = m+. + const diyfp w_plus = diyfp::normalize(m_plus); + + // Determine w- = m- such that e_(w-) = e_(w+). + const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); + + return {diyfp::normalize(v), w_minus, w_plus}; +} + +// Given normalized diyfp w, Grisu needs to find a (normalized) cached +// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies +// within a certain range [alpha, gamma] (Definition 3.2 from [1]) +// +// alpha <= e = e_c + e_w + q <= gamma +// +// or +// +// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q +// <= f_c * f_w * 2^gamma +// +// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies +// +// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma +// +// or +// +// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) +// +// The choice of (alpha,gamma) determines the size of the table and the form of +// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well +// in practice: +// +// The idea is to cut the number c * w = f * 2^e into two parts, which can be +// processed independently: An integral part p1, and a fractional part p2: +// +// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e +// = (f div 2^-e) + (f mod 2^-e) * 2^e +// = p1 + p2 * 2^e +// +// The conversion of p1 into decimal form requires a series of divisions and +// modulos by (a power of) 10. These operations are faster for 32-bit than for +// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be +// achieved by choosing +// +// -e >= 32 or e <= -32 := gamma +// +// In order to convert the fractional part +// +// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// into decimal form, the fraction is repeatedly multiplied by 10 and the digits +// d[-i] are extracted in order: +// +// (10 * p2) div 2^-e = d[-1] +// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... +// +// The multiplication by 10 must not overflow. It is sufficient to choose +// +// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. +// +// Since p2 = f mod 2^-e < 2^-e, +// +// -e <= 60 or e >= -60 := alpha + +constexpr int kAlpha = -60; +constexpr int kGamma = -32; + +struct cached_power // c = f * 2^e ~= 10^k +{ + std::uint64_t f; + int e; + int k; +}; + +/*! +For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached +power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c +satisfies (Definition 3.2 from [1]) + + alpha <= e_c + e + q <= gamma. +*/ +inline cached_power get_cached_power_for_binary_exponent(int e) +{ + // Now + // + // alpha <= e_c + e + q <= gamma (1) + // ==> f_c * 2^alpha <= c * 2^e * 2^q + // + // and since the c's are normalized, 2^(q-1) <= f_c, + // + // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) + // ==> 2^(alpha - e - 1) <= c + // + // If c were an exact power of ten, i.e. c = 10^k, one may determine k as + // + // k = ceil( log_10( 2^(alpha - e - 1) ) ) + // = ceil( (alpha - e - 1) * log_10(2) ) + // + // From the paper: + // "In theory the result of the procedure could be wrong since c is rounded, + // and the computation itself is approximated [...]. In practice, however, + // this simple function is sufficient." + // + // For IEEE double precision floating-point numbers converted into + // normalized diyfp's w = f * 2^e, with q = 64, + // + // e >= -1022 (min IEEE exponent) + // -52 (p - 1) + // -52 (p - 1, possibly normalize denormal IEEE numbers) + // -11 (normalize the diyfp) + // = -1137 + // + // and + // + // e <= +1023 (max IEEE exponent) + // -52 (p - 1) + // -11 (normalize the diyfp) + // = 960 + // + // This binary exponent range [-1137,960] results in a decimal exponent + // range [-307,324]. One does not need to store a cached power for each + // k in this range. For each such k it suffices to find a cached power + // such that the exponent of the product lies in [alpha,gamma]. + // This implies that the difference of the decimal exponents of adjacent + // table entries must be less than or equal to + // + // floor( (gamma - alpha) * log_10(2) ) = 8. + // + // (A smaller distance gamma-alpha would require a larger table.) + + // NB: + // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + + constexpr int kCachedPowersMinDecExp = -300; + constexpr int kCachedPowersDecStep = 8; + + static constexpr std::array kCachedPowers = + { + { + { 0xAB70FE17C79AC6CA, -1060, -300 }, + { 0xFF77B1FCBEBCDC4F, -1034, -292 }, + { 0xBE5691EF416BD60C, -1007, -284 }, + { 0x8DD01FAD907FFC3C, -980, -276 }, + { 0xD3515C2831559A83, -954, -268 }, + { 0x9D71AC8FADA6C9B5, -927, -260 }, + { 0xEA9C227723EE8BCB, -901, -252 }, + { 0xAECC49914078536D, -874, -244 }, + { 0x823C12795DB6CE57, -847, -236 }, + { 0xC21094364DFB5637, -821, -228 }, + { 0x9096EA6F3848984F, -794, -220 }, + { 0xD77485CB25823AC7, -768, -212 }, + { 0xA086CFCD97BF97F4, -741, -204 }, + { 0xEF340A98172AACE5, -715, -196 }, + { 0xB23867FB2A35B28E, -688, -188 }, + { 0x84C8D4DFD2C63F3B, -661, -180 }, + { 0xC5DD44271AD3CDBA, -635, -172 }, + { 0x936B9FCEBB25C996, -608, -164 }, + { 0xDBAC6C247D62A584, -582, -156 }, + { 0xA3AB66580D5FDAF6, -555, -148 }, + { 0xF3E2F893DEC3F126, -529, -140 }, + { 0xB5B5ADA8AAFF80B8, -502, -132 }, + { 0x87625F056C7C4A8B, -475, -124 }, + { 0xC9BCFF6034C13053, -449, -116 }, + { 0x964E858C91BA2655, -422, -108 }, + { 0xDFF9772470297EBD, -396, -100 }, + { 0xA6DFBD9FB8E5B88F, -369, -92 }, + { 0xF8A95FCF88747D94, -343, -84 }, + { 0xB94470938FA89BCF, -316, -76 }, + { 0x8A08F0F8BF0F156B, -289, -68 }, + { 0xCDB02555653131B6, -263, -60 }, + { 0x993FE2C6D07B7FAC, -236, -52 }, + { 0xE45C10C42A2B3B06, -210, -44 }, + { 0xAA242499697392D3, -183, -36 }, + { 0xFD87B5F28300CA0E, -157, -28 }, + { 0xBCE5086492111AEB, -130, -20 }, + { 0x8CBCCC096F5088CC, -103, -12 }, + { 0xD1B71758E219652C, -77, -4 }, + { 0x9C40000000000000, -50, 4 }, + { 0xE8D4A51000000000, -24, 12 }, + { 0xAD78EBC5AC620000, 3, 20 }, + { 0x813F3978F8940984, 30, 28 }, + { 0xC097CE7BC90715B3, 56, 36 }, + { 0x8F7E32CE7BEA5C70, 83, 44 }, + { 0xD5D238A4ABE98068, 109, 52 }, + { 0x9F4F2726179A2245, 136, 60 }, + { 0xED63A231D4C4FB27, 162, 68 }, + { 0xB0DE65388CC8ADA8, 189, 76 }, + { 0x83C7088E1AAB65DB, 216, 84 }, + { 0xC45D1DF942711D9A, 242, 92 }, + { 0x924D692CA61BE758, 269, 100 }, + { 0xDA01EE641A708DEA, 295, 108 }, + { 0xA26DA3999AEF774A, 322, 116 }, + { 0xF209787BB47D6B85, 348, 124 }, + { 0xB454E4A179DD1877, 375, 132 }, + { 0x865B86925B9BC5C2, 402, 140 }, + { 0xC83553C5C8965D3D, 428, 148 }, + { 0x952AB45CFA97A0B3, 455, 156 }, + { 0xDE469FBD99A05FE3, 481, 164 }, + { 0xA59BC234DB398C25, 508, 172 }, + { 0xF6C69A72A3989F5C, 534, 180 }, + { 0xB7DCBF5354E9BECE, 561, 188 }, + { 0x88FCF317F22241E2, 588, 196 }, + { 0xCC20CE9BD35C78A5, 614, 204 }, + { 0x98165AF37B2153DF, 641, 212 }, + { 0xE2A0B5DC971F303A, 667, 220 }, + { 0xA8D9D1535CE3B396, 694, 228 }, + { 0xFB9B7CD9A4A7443C, 720, 236 }, + { 0xBB764C4CA7A44410, 747, 244 }, + { 0x8BAB8EEFB6409C1A, 774, 252 }, + { 0xD01FEF10A657842C, 800, 260 }, + { 0x9B10A4E5E9913129, 827, 268 }, + { 0xE7109BFBA19C0C9D, 853, 276 }, + { 0xAC2820D9623BF429, 880, 284 }, + { 0x80444B5E7AA7CF85, 907, 292 }, + { 0xBF21E44003ACDD2D, 933, 300 }, + { 0x8E679C2F5E44FF8F, 960, 308 }, + { 0xD433179D9C8CB841, 986, 316 }, + { 0x9E19DB92B4E31BA9, 1013, 324 }, + } + }; + + // This computation gives exactly the same results for k as + // k = ceil((kAlpha - e - 1) * 0.30102999566398114) + // for |e| <= 1500, but doesn't require floating-point operations. + // NB: log_10(2) ~= 78913 / 2^18 + JSON_ASSERT(e >= -1500); + JSON_ASSERT(e <= 1500); + const int f = kAlpha - e - 1; + const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); + + const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; + JSON_ASSERT(index >= 0); + JSON_ASSERT(static_cast(index) < kCachedPowers.size()); + + const cached_power cached = kCachedPowers[static_cast(index)]; + JSON_ASSERT(kAlpha <= cached.e + e + 64); + JSON_ASSERT(kGamma >= cached.e + e + 64); + + return cached; +} + +/*! +For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. +For n == 0, returns 1 and sets pow10 := 1. +*/ +inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) +{ + // LCOV_EXCL_START + if (n >= 1000000000) + { + pow10 = 1000000000; + return 10; + } + // LCOV_EXCL_STOP + if (n >= 100000000) + { + pow10 = 100000000; + return 9; + } + if (n >= 10000000) + { + pow10 = 10000000; + return 8; + } + if (n >= 1000000) + { + pow10 = 1000000; + return 7; + } + if (n >= 100000) + { + pow10 = 100000; + return 6; + } + if (n >= 10000) + { + pow10 = 10000; + return 5; + } + if (n >= 1000) + { + pow10 = 1000; + return 4; + } + if (n >= 100) + { + pow10 = 100; + return 3; + } + if (n >= 10) + { + pow10 = 10; + return 2; + } + + pow10 = 1; + return 1; +} + +inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, + std::uint64_t rest, std::uint64_t ten_k) +{ + JSON_ASSERT(len >= 1); + JSON_ASSERT(dist <= delta); + JSON_ASSERT(rest <= delta); + JSON_ASSERT(ten_k > 0); + + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // ten_k + // <------> + // <---- rest ----> + // --------------[------------------+----+--------------]-------------- + // w V + // = buf * 10^k + // + // ten_k represents a unit-in-the-last-place in the decimal representation + // stored in buf. + // Decrement buf by ten_k while this takes buf closer to w. + + // The tests are written in this order to avoid overflow in unsigned + // integer arithmetic. + + while (rest < dist + && delta - rest >= ten_k + && (rest + ten_k < dist || dist - rest > rest + ten_k - dist)) + { + JSON_ASSERT(buf[len - 1] != '0'); + buf[len - 1]--; + rest += ten_k; + } +} + +/*! +Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. +M- and M+ must be normalized and share the same exponent -60 <= e <= -32. +*/ +inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, + diyfp M_minus, diyfp w, diyfp M_plus) +{ + static_assert(kAlpha >= -60, "internal error"); + static_assert(kGamma <= -32, "internal error"); + + // Generates the digits (and the exponent) of a decimal floating-point + // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's + // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. + // + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // Grisu2 generates the digits of M+ from left to right and stops as soon as + // V is in [M-,M+]. + + JSON_ASSERT(M_plus.e >= kAlpha); + JSON_ASSERT(M_plus.e <= kGamma); + + std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) + std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) + + // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): + // + // M+ = f * 2^e + // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e + // = ((p1 ) * 2^-e + (p2 )) * 2^e + // = p1 + p2 * 2^e + + const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e); + + auto p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) + std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e + + // 1) + // + // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] + + JSON_ASSERT(p1 > 0); + + std::uint32_t pow10{}; + const int k = find_largest_pow10(p1, pow10); + + // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) + // + // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) + // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) + // + // M+ = p1 + p2 * 2^e + // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e + // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e + // = d[k-1] * 10^(k-1) + ( rest) * 2^e + // + // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) + // + // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] + // + // but stop as soon as + // + // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e + + int n = k; + while (n > 0) + { + // Invariants: + // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) + // pow10 = 10^(n-1) <= p1 < 10^n + // + const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) + const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) + // + // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e + // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) + // + p1 = r; + n--; + // + // M+ = buffer * 10^n + (p1 + p2 * 2^e) + // pow10 = 10^n + // + + // Now check if enough digits have been generated. + // Compute + // + // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e + // + // Note: + // Since rest and delta share the same exponent e, it suffices to + // compare the significands. + const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2; + if (rest <= delta) + { + // V = buffer * 10^n, with M- <= V <= M+. + + decimal_exponent += n; + + // We may now just stop. But instead look if the buffer could be + // decremented to bring V closer to w. + // + // pow10 = 10^n is now 1 ulp in the decimal representation V. + // The rounding procedure works with diyfp's with an implicit + // exponent of e. + // + // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e + // + const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e; + grisu2_round(buffer, length, dist, delta, rest, ten_n); + + return; + } + + pow10 /= 10; + // + // pow10 = 10^(n-1) <= p1 < 10^n + // Invariants restored. + } + + // 2) + // + // The digits of the integral part have been generated: + // + // M+ = d[k-1]...d[1]d[0] + p2 * 2^e + // = buffer + p2 * 2^e + // + // Now generate the digits of the fractional part p2 * 2^e. + // + // Note: + // No decimal point is generated: the exponent is adjusted instead. + // + // p2 actually represents the fraction + // + // p2 * 2^e + // = p2 / 2^-e + // = d[-1] / 10^1 + d[-2] / 10^2 + ... + // + // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) + // + // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m + // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) + // + // using + // + // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) + // = ( d) * 2^-e + ( r) + // + // or + // 10^m * p2 * 2^e = d + r * 2^e + // + // i.e. + // + // M+ = buffer + p2 * 2^e + // = buffer + 10^-m * (d + r * 2^e) + // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e + // + // and stop as soon as 10^-m * r * 2^e <= delta * 2^e + + JSON_ASSERT(p2 > delta); + + int m = 0; + for (;;) + { + // Invariant: + // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e + // = buffer * 10^-m + 10^-m * (p2 ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e + // + JSON_ASSERT(p2 <= (std::numeric_limits::max)() / 10); + p2 *= 10; + const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e + const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e + // + // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) + // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + p2 = r; + m++; + // + // M+ = buffer * 10^-m + 10^-m * p2 * 2^e + // Invariant restored. + + // Check if enough digits have been generated. + // + // 10^-m * p2 * 2^e <= delta * 2^e + // p2 * 2^e <= 10^m * delta * 2^e + // p2 <= 10^m * delta + delta *= 10; + dist *= 10; + if (p2 <= delta) + { + break; + } + } + + // V = buffer * 10^-m, with M- <= V <= M+. + + decimal_exponent -= m; + + // 1 ulp in the decimal representation is now 10^-m. + // Since delta and dist are now scaled by 10^m, we need to do the + // same with ulp in order to keep the units in sync. + // + // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e + // + const std::uint64_t ten_m = one.f; + grisu2_round(buffer, length, dist, delta, p2, ten_m); + + // By construction this algorithm generates the shortest possible decimal + // number (Loitsch, Theorem 6.2) which rounds back to w. + // For an input number of precision p, at least + // + // N = 1 + ceil(p * log_10(2)) + // + // decimal digits are sufficient to identify all binary floating-point + // numbers (Matula, "In-and-Out conversions"). + // This implies that the algorithm does not produce more than N decimal + // digits. + // + // N = 17 for p = 53 (IEEE double precision) + // N = 9 for p = 24 (IEEE single precision) +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +JSON_HEDLEY_NON_NULL(1) +inline void grisu2(char* buf, int& len, int& decimal_exponent, + diyfp m_minus, diyfp v, diyfp m_plus) +{ + JSON_ASSERT(m_plus.e == m_minus.e); + JSON_ASSERT(m_plus.e == v.e); + + // --------(-----------------------+-----------------------)-------- (A) + // m- v m+ + // + // --------------------(-----------+-----------------------)-------- (B) + // m- v m+ + // + // First scale v (and m- and m+) such that the exponent is in the range + // [alpha, gamma]. + + const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); + + const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k + + // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] + const diyfp w = diyfp::mul(v, c_minus_k); + const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); + const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); + + // ----(---+---)---------------(---+---)---------------(---+---)---- + // w- w w+ + // = c*m- = c*v = c*m+ + // + // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and + // w+ are now off by a small amount. + // In fact: + // + // w - v * 10^k < 1 ulp + // + // To account for this inaccuracy, add resp. subtract 1 ulp. + // + // --------+---[---------------(---+---)---------------]---+-------- + // w- M- w M+ w+ + // + // Now any number in [M-, M+] (bounds included) will round to w when input, + // regardless of how the input rounding algorithm breaks ties. + // + // And digit_gen generates the shortest possible such number in [M-, M+]. + // Note that this does not mean that Grisu2 always generates the shortest + // possible number in the interval (m-, m+). + const diyfp M_minus(w_minus.f + 1, w_minus.e); + const diyfp M_plus (w_plus.f - 1, w_plus.e ); + + decimal_exponent = -cached.k; // = -(-k) = k + + grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +template +JSON_HEDLEY_NON_NULL(1) +void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) +{ + static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, + "internal error: not enough precision"); + + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // If the neighbors (and boundaries) of 'value' are always computed for double-precision + // numbers, all float's can be recovered using strtod (and strtof). However, the resulting + // decimal representations are not exactly "short". + // + // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars) + // says "value is converted to a string as if by std::sprintf in the default ("C") locale" + // and since sprintf promotes floats to doubles, I think this is exactly what 'std::to_chars' + // does. + // On the other hand, the documentation for 'std::to_chars' requires that "parsing the + // representation using the corresponding std::from_chars function recovers value exactly". That + // indicates that single precision floating-point numbers should be recovered using + // 'std::strtof'. + // + // NB: If the neighbors are computed for single-precision numbers, there is a single float + // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision + // value is off by 1 ulp. +#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if) + const boundaries w = compute_boundaries(static_cast(value)); +#else + const boundaries w = compute_boundaries(value); +#endif + + grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); +} + +/*! +@brief appends a decimal representation of e to buf +@return a pointer to the element following the exponent. +@pre -1000 < e < 1000 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* append_exponent(char* buf, int e) +{ + JSON_ASSERT(e > -1000); + JSON_ASSERT(e < 1000); + + if (e < 0) + { + e = -e; + *buf++ = '-'; + } + else + { + *buf++ = '+'; + } + + auto k = static_cast(e); + if (k < 10) + { + // Always print at least two digits in the exponent. + // This is for compatibility with printf("%g"). + *buf++ = '0'; + *buf++ = static_cast('0' + k); + } + else if (k < 100) + { + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + else + { + *buf++ = static_cast('0' + k / 100); + k %= 100; + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + + return buf; +} + +/*! +@brief prettify v = buf * 10^decimal_exponent + +If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point +notation. Otherwise it will be printed in exponential notation. + +@pre min_exp < 0 +@pre max_exp > 0 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* format_buffer(char* buf, int len, int decimal_exponent, + int min_exp, int max_exp) +{ + JSON_ASSERT(min_exp < 0); + JSON_ASSERT(max_exp > 0); + + const int k = len; + const int n = len + decimal_exponent; + + // v = buf * 10^(n-k) + // k is the length of the buffer (number of decimal digits) + // n is the position of the decimal point relative to the start of the buffer. + + if (k <= n && n <= max_exp) + { + // digits[000] + // len <= max_exp + 2 + + std::memset(buf + k, '0', static_cast(n) - static_cast(k)); + // Make it look like a floating-point number (#362, #378) + buf[n + 0] = '.'; + buf[n + 1] = '0'; + return buf + (static_cast(n) + 2); + } + + if (0 < n && n <= max_exp) + { + // dig.its + // len <= max_digits10 + 1 + + JSON_ASSERT(k > n); + + std::memmove(buf + (static_cast(n) + 1), buf + n, static_cast(k) - static_cast(n)); + buf[n] = '.'; + return buf + (static_cast(k) + 1U); + } + + if (min_exp < n && n <= 0) + { + // 0.[000]digits + // len <= 2 + (-min_exp - 1) + max_digits10 + + std::memmove(buf + (2 + static_cast(-n)), buf, static_cast(k)); + buf[0] = '0'; + buf[1] = '.'; + std::memset(buf + 2, '0', static_cast(-n)); + return buf + (2U + static_cast(-n) + static_cast(k)); + } + + if (k == 1) + { + // dE+123 + // len <= 1 + 5 + + buf += 1; + } + else + { + // d.igitsE+123 + // len <= max_digits10 + 1 + 5 + + std::memmove(buf + 2, buf + 1, static_cast(k) - 1); + buf[1] = '.'; + buf += 1 + static_cast(k); + } + + *buf++ = 'e'; + return append_exponent(buf, n - 1); +} + +} // namespace dtoa_impl + +/*! +@brief generates a decimal representation of the floating-point number value in [first, last). + +The format of the resulting decimal representation is similar to printf's %g +format. Returns an iterator pointing past-the-end of the decimal representation. + +@note The input number must be finite, i.e. NaN's and Inf's are not supported. +@note The buffer must be large enough. +@note The result is NOT null-terminated. +*/ +template +JSON_HEDLEY_NON_NULL(1, 2) +JSON_HEDLEY_RETURNS_NON_NULL +char* to_chars(char* first, const char* last, FloatType value) +{ + static_cast(last); // maybe unused - fix warning + JSON_ASSERT(std::isfinite(value)); + + // Use signbit(value) instead of (value < 0) since signbit works for -0. + if (std::signbit(value)) + { + value = -value; + *first++ = '-'; + } + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + if (value == 0) // +-0 + { + *first++ = '0'; + // Make it look like a floating-point number (#362, #378) + *first++ = '.'; + *first++ = '0'; + return first; + } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); + + // Compute v = buffer * 10^decimal_exponent. + // The decimal digits are stored in the buffer, which needs to be interpreted + // as an unsigned decimal integer. + // len is the length of the buffer, i.e. the number of decimal digits. + int len = 0; + int decimal_exponent = 0; + dtoa_impl::grisu2(first, len, decimal_exponent, value); + + JSON_ASSERT(len <= std::numeric_limits::max_digits10); + + // Format the buffer like printf("%.*g", prec, value) + constexpr int kMinExp = -4; + // Use digits10 here to increase compatibility with version 2. + constexpr int kMaxExp = std::numeric_limits::digits10; + + JSON_ASSERT(last - first >= kMaxExp + 2); + JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10 + 6); + + return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/conversions/to_json.hpp b/json/include/nlohmann/detail/conversions/to_json.hpp new file mode 100644 index 0000000..e39b779 --- /dev/null +++ b/json/include/nlohmann/detail/conversions/to_json.hpp @@ -0,0 +1,446 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // copy +#include // begin, end +#include // string +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +////////////////// +// constructors // +////////////////// + +/* + * Note all external_constructor<>::construct functions need to call + * j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an + * allocated value (e.g., a string). See bug issue + * https://github.com/nlohmann/json/issues/2865 for more information. + */ + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::boolean; + j.m_data.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::string; + j.m_data.m_value = s; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::string; + j.m_data.m_value = std::move(s); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleStringType, + enable_if_t < !std::is_same::value, + int > = 0 > + static void construct(BasicJsonType& j, const CompatibleStringType& str) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::string; + j.m_data.m_value.string = j.template create(str); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::binary; + j.m_data.m_value = typename BasicJsonType::binary_t(b); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::binary; + j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b)); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::number_float; + j.m_data.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::number_unsigned; + j.m_data.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::number_integer; + j.m_data.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::array; + j.m_data.m_value = arr; + j.set_parents(); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::array; + j.m_data.m_value = std::move(arr); + j.set_parents(); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < !std::is_same::value, + int > = 0 > + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::array; + j.m_data.m_value.array = j.template create(begin(arr), end(arr)); + j.set_parents(); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, const std::vector& arr) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::array; + j.m_data.m_value = value_t::array; + j.m_data.m_value.array->reserve(arr.size()); + for (const bool x : arr) + { + j.m_data.m_value.array->push_back(x); + j.set_parent(j.m_data.m_value.array->back()); + } + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const std::valarray& arr) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::array; + j.m_data.m_value = value_t::array; + j.m_data.m_value.array->resize(arr.size()); + if (arr.size() > 0) + { + std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin()); + } + j.set_parents(); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::object; + j.m_data.m_value = obj; + j.set_parents(); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::object; + j.m_data.m_value = std::move(obj); + j.set_parents(); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < !std::is_same::value, int > = 0 > + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::object; + j.m_data.m_value.object = j.template create(begin(obj), end(obj)); + j.set_parents(); + j.assert_invariant(); + } +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template < typename BasicJsonType, typename BoolRef, + enable_if_t < + ((std::is_same::reference, BoolRef>::value + && !std::is_same ::reference, typename BasicJsonType::boolean_t&>::value) + || (std::is_same::const_reference, BoolRef>::value + && !std::is_same ::const_reference>, + typename BasicJsonType::boolean_t >::value)) + && std::is_convertible::value, int > = 0 > +inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept +{ + external_constructor::construct(j, static_cast(b)); +} + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template +inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ + external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +#if !JSON_DISABLE_ENUM_SERIALIZATION +template::value, int> = 0> +inline void to_json(BasicJsonType& j, EnumType e) noexcept +{ + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); +} +#endif // JSON_DISABLE_ENUM_SERIALIZATION + +template +inline void to_json(BasicJsonType& j, const std::vector& e) +{ + external_constructor::construct(j, e); +} + +template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < is_compatible_array_type::value&& + !is_compatible_object_type::value&& + !is_compatible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > +inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template +inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) +{ + external_constructor::construct(j, bin); +} + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, const std::valarray& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template +inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < is_compatible_object_type::value&& !is_basic_json::value, int > = 0 > +inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ + external_constructor::construct(j, obj); +} + +template +inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ + external_constructor::construct(j, std::move(obj)); +} + +template < + typename BasicJsonType, typename T, std::size_t N, + enable_if_t < !std::is_constructible::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + int > = 0 > +inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +{ + external_constructor::construct(j, arr); +} + +template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible::value&& std::is_constructible::value, int > = 0 > +inline void to_json(BasicJsonType& j, const std::pair& p) +{ + j = { p.first, p.second }; +} + +// for https://github.com/nlohmann/json/pull/1134 +template>::value, int> = 0> +inline void to_json(BasicJsonType& j, const T& b) +{ + j = { {b.key(), b.value()} }; +} + +template +inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) +{ + j = { std::get(t)... }; +} + +template::value, int > = 0> +inline void to_json(BasicJsonType& j, const T& t) +{ + to_json_tuple_impl(j, t, make_index_sequence::value> {}); +} + +#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM +template +inline void to_json(BasicJsonType& j, const std_fs::path& p) +{ + j = p.string(); +} +#endif + +struct to_json_fn +{ + template + auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } +}; +} // namespace detail + +#ifndef JSON_HAS_CPP_17 +/// namespace to hold default `to_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) +{ +#endif +JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers) + detail::static_const::value; +#ifndef JSON_HAS_CPP_17 +} // namespace +#endif + +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/exceptions.hpp b/json/include/nlohmann/detail/exceptions.hpp new file mode 100644 index 0000000..5974d7b --- /dev/null +++ b/json/include/nlohmann/detail/exceptions.hpp @@ -0,0 +1,257 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // nullptr_t +#include // exception +#if JSON_DIAGNOSTICS + #include // accumulate +#endif +#include // runtime_error +#include // to_string +#include // vector + +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +//////////////// +// exceptions // +//////////////// + +/// @brief general exception of the @ref basic_json class +/// @sa https://json.nlohmann.me/api/basic_json/exception/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes) + + protected: + JSON_HEDLEY_NON_NULL(3) + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing) + + static std::string name(const std::string& ename, int id_) + { + return concat("[json.exception.", ename, '.', std::to_string(id_), "] "); + } + + static std::string diagnostics(std::nullptr_t /*leaf_element*/) + { + return ""; + } + + template + static std::string diagnostics(const BasicJsonType* leaf_element) + { +#if JSON_DIAGNOSTICS + std::vector tokens; + for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent) + { + switch (current->m_parent->type()) + { + case value_t::array: + { + for (std::size_t i = 0; i < current->m_parent->m_data.m_value.array->size(); ++i) + { + if (¤t->m_parent->m_data.m_value.array->operator[](i) == current) + { + tokens.emplace_back(std::to_string(i)); + break; + } + } + break; + } + + case value_t::object: + { + for (const auto& element : *current->m_parent->m_data.m_value.object) + { + if (&element.second == current) + { + tokens.emplace_back(element.first.c_str()); + break; + } + } + break; + } + + case value_t::null: // LCOV_EXCL_LINE + case value_t::string: // LCOV_EXCL_LINE + case value_t::boolean: // LCOV_EXCL_LINE + case value_t::number_integer: // LCOV_EXCL_LINE + case value_t::number_unsigned: // LCOV_EXCL_LINE + case value_t::number_float: // LCOV_EXCL_LINE + case value_t::binary: // LCOV_EXCL_LINE + case value_t::discarded: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + break; // LCOV_EXCL_LINE + } + } + + if (tokens.empty()) + { + return ""; + } + + auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, + [](const std::string & a, const std::string & b) + { + return concat(a, '/', detail::escape(b)); + }); + return concat('(', str, ") "); +#else + static_cast(leaf_element); + return ""; +#endif + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/// @brief exception indicating a parse error +/// @sa https://json.nlohmann.me/api/basic_json/parse_error/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + template::value, int> = 0> + static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("parse_error", id_), "parse error", + position_string(pos), ": ", exception::diagnostics(context), what_arg); + return {id_, pos.chars_read_total, w.c_str()}; + } + + template::value, int> = 0> + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("parse_error", id_), "parse error", + (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""), + ": ", exception::diagnostics(context), what_arg); + return {id_, byte_, w.c_str()}; + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return concat(" at line ", std::to_string(pos.lines_read + 1), + ", column ", std::to_string(pos.chars_read_current_line)); + } +}; + +/// @brief exception indicating errors with iterators +/// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/ +class invalid_iterator : public exception +{ + public: + template::value, int> = 0> + static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg); + return {id_, w.c_str()}; + } + + private: + JSON_HEDLEY_NON_NULL(3) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/// @brief exception indicating executing a member function with a wrong type +/// @sa https://json.nlohmann.me/api/basic_json/type_error/ +class type_error : public exception +{ + public: + template::value, int> = 0> + static type_error create(int id_, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg); + return {id_, w.c_str()}; + } + + private: + JSON_HEDLEY_NON_NULL(3) + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/// @brief exception indicating access out of the defined range +/// @sa https://json.nlohmann.me/api/basic_json/out_of_range/ +class out_of_range : public exception +{ + public: + template::value, int> = 0> + static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg); + return {id_, w.c_str()}; + } + + private: + JSON_HEDLEY_NON_NULL(3) + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/// @brief exception indicating other library errors +/// @sa https://json.nlohmann.me/api/basic_json/other_error/ +class other_error : public exception +{ + public: + template::value, int> = 0> + static other_error create(int id_, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg); + return {id_, w.c_str()}; + } + + private: + JSON_HEDLEY_NON_NULL(3) + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/hash.hpp b/json/include/nlohmann/detail/hash.hpp new file mode 100644 index 0000000..4464e8e --- /dev/null +++ b/json/include/nlohmann/detail/hash.hpp @@ -0,0 +1,129 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // uint8_t +#include // size_t +#include // hash + +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// boost::hash_combine +inline std::size_t combine(std::size_t seed, std::size_t h) noexcept +{ + seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); + return seed; +} + +/*! +@brief hash a JSON value + +The hash function tries to rely on std::hash where possible. Furthermore, the +type of the JSON value is taken into account to have different hash values for +null, 0, 0U, and false, etc. + +@tparam BasicJsonType basic_json specialization +@param j JSON value to hash +@return hash value of j +*/ +template +std::size_t hash(const BasicJsonType& j) +{ + using string_t = typename BasicJsonType::string_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + + const auto type = static_cast(j.type()); + switch (j.type()) + { + case BasicJsonType::value_t::null: + case BasicJsonType::value_t::discarded: + { + return combine(type, 0); + } + + case BasicJsonType::value_t::object: + { + auto seed = combine(type, j.size()); + for (const auto& element : j.items()) + { + const auto h = std::hash {}(element.key()); + seed = combine(seed, h); + seed = combine(seed, hash(element.value())); + } + return seed; + } + + case BasicJsonType::value_t::array: + { + auto seed = combine(type, j.size()); + for (const auto& element : j) + { + seed = combine(seed, hash(element)); + } + return seed; + } + + case BasicJsonType::value_t::string: + { + const auto h = std::hash {}(j.template get_ref()); + return combine(type, h); + } + + case BasicJsonType::value_t::boolean: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_integer: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_unsigned: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_float: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::binary: + { + auto seed = combine(type, j.get_binary().size()); + const auto h = std::hash {}(j.get_binary().has_subtype()); + seed = combine(seed, h); + seed = combine(seed, static_cast(j.get_binary().subtype())); + for (const auto byte : j.get_binary()) + { + seed = combine(seed, std::hash {}(byte)); + } + return seed; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + return 0; // LCOV_EXCL_LINE + } +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/input/binary_reader.hpp b/json/include/nlohmann/detail/input/binary_reader.hpp new file mode 100644 index 0000000..a6e100e --- /dev/null +++ b/json/include/nlohmann/detail/input/binary_reader.hpp @@ -0,0 +1,3009 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // generate_n +#include // array +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // snprintf +#include // memcpy +#include // back_inserter +#include // numeric_limits +#include // char_traits, string +#include // make_pair, move +#include // vector + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// how to treat CBOR tags +enum class cbor_tag_handler_t +{ + error, ///< throw a parse_error exception in case of a tag + ignore, ///< ignore tags + store ///< store tags as binary type +}; + +/*! +@brief determine system byte order + +@return true if and only if system's byte order is little endian + +@note from https://stackoverflow.com/a/1001328/266378 +*/ +static inline bool little_endianness(int num = 1) noexcept +{ + return *reinterpret_cast(&num) == 1; +} + +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR, MessagePack, and UBJSON values +*/ +template> +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using json_sax_t = SAX; + using char_type = typename InputAdapterType::char_type; + using char_int_type = typename char_traits::int_type; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json) noexcept : ia(std::move(adapter)), input_format(format) + { + (void)detail::is_sax_static_asserts {}; + } + + // make class move-only + binary_reader(const binary_reader&) = delete; + binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + binary_reader& operator=(const binary_reader&) = delete; + binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~binary_reader() = default; + + /*! + @param[in] format the binary format to parse + @param[in] sax_ a SAX event processor + @param[in] strict whether to expect the input to be consumed completed + @param[in] tag_handler how to treat CBOR tags + + @return whether parsing was successful + */ + JSON_HEDLEY_NON_NULL(3) + bool sax_parse(const input_format_t format, + json_sax_t* sax_, + const bool strict = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + sax = sax_; + bool result = false; + + switch (format) + { + case input_format_t::bson: + result = parse_bson_internal(); + break; + + case input_format_t::cbor: + result = parse_cbor_internal(true, tag_handler); + break; + + case input_format_t::msgpack: + result = parse_msgpack_internal(); + break; + + case input_format_t::ubjson: + case input_format_t::bjdata: + result = parse_ubjson_internal(); + break; + + case input_format_t::json: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + + // strict mode: next byte must be EOF + if (result && strict) + { + if (input_format == input_format_t::ubjson || input_format == input_format_t::bjdata) + { + get_ignore_noop(); + } + else + { + get(); + } + + if (JSON_HEDLEY_UNLIKELY(current != char_traits::eof())) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, + exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr)); + } + } + + return result; + } + + private: + ////////// + // BSON // + ////////// + + /*! + @brief Reads in a BSON-object and passes it to the SAX-parser. + @return whether a valid BSON-value was passed to the SAX parser + */ + bool parse_bson_internal() + { + std::int32_t document_size{}; + get_number(input_format_t::bson, document_size); + + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false))) + { + return false; + } + + return sax->end_object(); + } + + /*! + @brief Parses a C-style string from the BSON input. + @param[in,out] result A reference to the string variable where the read + string is to be stored. + @return `true` if the \x00-byte indicating the end of the string was + encountered before the EOF; false` indicates an unexpected EOF. + */ + bool get_bson_cstr(string_t& result) + { + auto out = std::back_inserter(result); + while (true) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) + { + return false; + } + if (current == 0x00) + { + return true; + } + *out++ = static_cast(current); + } + } + + /*! + @brief Parses a zero-terminated string of length @a len from the BSON + input. + @param[in] len The length (including the zero-byte at the end) of the + string to be read. + @param[in,out] result A reference to the string variable where the read + string is to be stored. + @tparam NumberType The type of the length @a len + @pre len >= 1 + @return `true` if the string was successfully parsed + */ + template + bool get_bson_string(const NumberType len, string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(len < 1)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr)); + } + + return get_string(input_format_t::bson, len - static_cast(1), result) && get() != char_traits::eof(); + } + + /*! + @brief Parses a byte array input of length @a len from the BSON input. + @param[in] len The length of the byte array to be read. + @param[in,out] result A reference to the binary variable where the read + array is to be stored. + @tparam NumberType The type of the length @a len + @pre len >= 0 + @return `true` if the byte array was successfully parsed + */ + template + bool get_bson_binary(const NumberType len, binary_t& result) + { + if (JSON_HEDLEY_UNLIKELY(len < 0)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr)); + } + + // All BSON binary values have a subtype + std::uint8_t subtype{}; + get_number(input_format_t::bson, subtype); + result.set_subtype(subtype); + + return get_binary(input_format_t::bson, len, result); + } + + /*! + @brief Read a BSON document element of the given @a element_type. + @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html + @param[in] element_type_parse_position The position in the input stream, + where the `element_type` was read. + @warning Not all BSON element types are supported yet. An unsupported + @a element_type will give rise to a parse_error.114: + Unsupported BSON record type 0x... + @return whether a valid BSON-object/array was passed to the SAX parser + */ + bool parse_bson_element_internal(const char_int_type element_type, + const std::size_t element_type_parse_position) + { + switch (element_type) + { + case 0x01: // double + { + double number{}; + return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); + } + + case 0x02: // string + { + std::int32_t len{}; + string_t value; + return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); + } + + case 0x03: // object + { + return parse_bson_internal(); + } + + case 0x04: // array + { + return parse_bson_array(); + } + + case 0x05: // binary + { + std::int32_t len{}; + binary_t value; + return get_number(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); + } + + case 0x08: // boolean + { + return sax->boolean(get() != 0); + } + + case 0x0A: // null + { + return sax->null(); + } + + case 0x10: // int32 + { + std::int32_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); + } + + case 0x12: // int64 + { + std::int64_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); + } + + default: // anything else not supported (yet) + { + std::array cr{{}}; + static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + const std::string cr_str{cr.data()}; + return sax->parse_error(element_type_parse_position, cr_str, + parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr)); + } + } + } + + /*! + @brief Read a BSON element list (as specified in the BSON-spec) + + The same binary layout is used for objects and arrays, hence it must be + indicated with the argument @a is_array which one is expected + (true --> array, false --> object). + + @param[in] is_array Determines if the element list being read is to be + treated as an object (@a is_array == false), or as an + array (@a is_array == true). + @return whether a valid BSON-object/array was passed to the SAX parser + */ + bool parse_bson_element_list(const bool is_array) + { + string_t key; + + while (auto element_type = get()) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) + { + return false; + } + + const std::size_t element_type_parse_position = chars_read; + if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key))) + { + return false; + } + + if (!is_array && !sax->key(key)) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position))) + { + return false; + } + + // get_bson_cstr only appends + key.clear(); + } + + return true; + } + + /*! + @brief Reads an array from the BSON input and passes it to the SAX-parser. + @return whether a valid BSON-array was passed to the SAX parser + */ + bool parse_bson_array() + { + std::int32_t document_size{}; + get_number(input_format_t::bson, document_size); + + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true))) + { + return false; + } + + return sax->end_array(); + } + + ////////// + // CBOR // + ////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true) or whether the last read character should + be considered instead (false) + @param[in] tag_handler how CBOR tags should be treated + + @return whether a valid CBOR value was passed to the SAX parser + */ + bool parse_cbor_internal(const bool get_char, + const cbor_tag_handler_t tag_handler) + { + switch (get_char ? get() : current) + { + // EOF + case char_traits::eof(): + return unexpect_eof(input_format_t::cbor, "value"); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return sax->number_unsigned(static_cast(current)); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return sax->number_integer(static_cast(0x20 - 1 - current)); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) + - static_cast(number)); + } + + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: // Binary data (one-byte uint8_t for n follows) + case 0x59: // Binary data (two-byte uint16_t for n follow) + case 0x5A: // Binary data (four-byte uint32_t for n follow) + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + case 0x5F: // Binary data (indefinite length) + { + binary_t b; + return get_cbor_binary(b) && sax->binary(b); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + string_t s; + return get_cbor_string(s) && sax->string(s); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + return get_cbor_array( + conditional_static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0x98: // array (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast(len), tag_handler); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast(len), tag_handler); + } + + case 0x9F: // array (indefinite length) + return get_cbor_array(static_cast(-1), tag_handler); + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + return get_cbor_object(conditional_static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0xB8: // map (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast(len), tag_handler); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast(len), tag_handler); + } + + case 0xBF: // map (indefinite length) + return get_cbor_object(static_cast(-1), tag_handler); + + case 0xC6: // tagged item + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD8: // tagged item (1 bytes follow) + case 0xD9: // tagged item (2 bytes follow) + case 0xDA: // tagged item (4 bytes follow) + case 0xDB: // tagged item (8 bytes follow) + { + switch (tag_handler) + { + case cbor_tag_handler_t::error: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + } + + case cbor_tag_handler_t::ignore: + { + // ignore binary subtype + switch (current) + { + case 0xD8: + { + std::uint8_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xD9: + { + std::uint16_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xDA: + { + std::uint32_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xDB: + { + std::uint64_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + default: + break; + } + return parse_cbor_internal(true, tag_handler); + } + + case cbor_tag_handler_t::store: + { + binary_t b; + // use binary subtype and store in binary container + switch (current) + { + case 0xD8: + { + std::uint8_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xD9: + { + std::uint16_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDA: + { + std::uint32_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDB: + { + std::uint64_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + default: + return parse_cbor_internal(true, tag_handler); + } + get(); + return get_cbor_binary(b) && sax->binary(b); + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + return false; // LCOV_EXCL_LINE + } + } + + case 0xF4: // false + return sax->boolean(false); + + case 0xF5: // true + return sax->boolean(true); + + case 0xF6: // null + return sax->null(); + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const auto half = static_cast((byte1 << 8u) + byte2); + const double val = [&half] + { + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); + switch (exp) + { + case 0: + return std::ldexp(mant, -24); + case 31: + return (mant == 0) + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + default: + return std::ldexp(mant + 1024, exp - 25); + } + }(); + return sax->number_float((half & 0x8000u) != 0 + ? static_cast(-val) + : static_cast(val), ""); + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + float number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + double number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + default: // anything else (0xFF is handled inside the other types) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + } + } + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_cbor_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) + { + return false; + } + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + while (get() != 0xFF) + { + string_t chunk; + if (!get_cbor_string(chunk)) + { + return false; + } + result.append(chunk); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr)); + } + } + } + + /*! + @brief reads a CBOR byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into the byte array. + Additionally, CBOR's byte arrays with indefinite lengths are supported. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_cbor_binary(binary_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) + { + return false; + } + + switch (current) + { + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + { + return get_binary(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x58: // Binary data (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x59: // Binary data (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5A: // Binary data (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5F: // Binary data (indefinite length) + { + while (get() != 0xFF) + { + binary_t chunk; + if (!get_cbor_binary(chunk)) + { + return false; + } + result.insert(result.end(), chunk.begin(), chunk.end()); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr)); + } + } + } + + /*! + @param[in] len the length of the array or static_cast(-1) for an + array of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether array creation completed + */ + bool get_cbor_array(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + if (len != static_cast(-1)) + { + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler))) + { + return false; + } + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object or static_cast(-1) for an + object of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether object creation completed + */ + bool get_cbor_object(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + if (len != 0) + { + string_t key; + if (len != static_cast(-1)) + { + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + } + + return sax->end_object(); + } + + ///////////// + // MsgPack // + ///////////// + + /*! + @return whether a valid MessagePack value was passed to the SAX parser + */ + bool parse_msgpack_internal() + { + switch (get()) + { + // EOF + case char_traits::eof(): + return unexpect_eof(input_format_t::msgpack, "value"); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return sax->number_unsigned(static_cast(current)); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + return get_msgpack_object(conditional_static_cast(static_cast(current) & 0x0Fu)); + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + return get_msgpack_array(conditional_static_cast(static_cast(current) & 0x0Fu)); + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + { + string_t s; + return get_msgpack_string(s) && sax->string(s); + } + + case 0xC0: // nil + return sax->null(); + + case 0xC2: // false + return sax->boolean(false); + + case 0xC3: // true + return sax->boolean(true); + + case 0xC4: // bin 8 + case 0xC5: // bin 16 + case 0xC6: // bin 32 + case 0xC7: // ext 8 + case 0xC8: // ext 16 + case 0xC9: // ext 32 + case 0xD4: // fixext 1 + case 0xD5: // fixext 2 + case 0xD6: // fixext 4 + case 0xD7: // fixext 8 + case 0xD8: // fixext 16 + { + binary_t b; + return get_msgpack_binary(b) && sax->binary(b); + } + + case 0xCA: // float 32 + { + float number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCB: // float 64 + { + double number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCC: // uint 8 + { + std::uint8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCD: // uint 16 + { + std::uint16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCE: // uint 32 + { + std::uint32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCF: // uint 64 + { + std::uint64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xD0: // int 8 + { + std::int8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD1: // int 16 + { + std::int16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD2: // int 32 + { + std::int32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD3: // int 64 + { + std::int64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xDC: // array 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); + } + + case 0xDD: // array 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast(len)); + } + + case 0xDE: // map 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); + } + + case 0xDF: // map 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast(len)); + } + + // negative fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return sax->number_integer(static_cast(current)); + + default: // anything else + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr)); + } + } + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_msgpack_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) + { + return false; + } + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(input_format_t::msgpack, static_cast(current) & 0x1Fu, result); + } + + case 0xD9: // str 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDA: // str 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDB: // str 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr)); + } + } + } + + /*! + @brief reads a MessagePack byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into a byte array. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_msgpack_binary(binary_t& result) + { + // helper function to set the subtype + auto assign_and_return_true = [&result](std::int8_t subtype) + { + result.set_subtype(static_cast(subtype)); + return true; + }; + + switch (current) + { + case 0xC4: // bin 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC5: // bin 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC6: // bin 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC7: // ext 8 + { + std::uint8_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC8: // ext 16 + { + std::uint16_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC9: // ext 32 + { + std::uint32_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xD4: // fixext 1 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 1, result) && + assign_and_return_true(subtype); + } + + case 0xD5: // fixext 2 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 2, result) && + assign_and_return_true(subtype); + } + + case 0xD6: // fixext 4 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 4, result) && + assign_and_return_true(subtype); + } + + case 0xD7: // fixext 8 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 8, result) && + assign_and_return_true(subtype); + } + + case 0xD8: // fixext 16 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 16, result) && + assign_and_return_true(subtype); + } + + default: // LCOV_EXCL_LINE + return false; // LCOV_EXCL_LINE + } + } + + /*! + @param[in] len the length of the array + @return whether array creation completed + */ + bool get_msgpack_array(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object + @return whether object creation completed + */ + bool get_msgpack_object(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + string_t key; + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + key.clear(); + } + + return sax->end_object(); + } + + //////////// + // UBJSON // + //////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether a valid UBJSON value was passed to the SAX parser + */ + bool parse_ubjson_internal(const bool get_char = true) + { + return get_ubjson_value(get_char ? get_ignore_noop() : current); + } + + /*! + @brief reads a UBJSON string + + This function is either called after reading the 'S' byte explicitly + indicating a string, or in case of an object key where the 'S' byte can be + left out. + + @param[out] result created string + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether string creation completed + */ + bool get_ubjson_string(string_t& result, const bool get_char = true) + { + if (get_char) + { + get(); // TODO(niels): may we ignore N here? + } + + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) + { + return false; + } + + switch (current) + { + case 'U': + { + std::uint8_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'i': + { + std::int8_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'I': + { + std::int16_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'l': + { + std::int32_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'L': + { + std::int64_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + default: + break; + } + auto last_token = get_token_string(); + std::string message; + + if (input_format != input_format_t::bjdata) + { + message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token; + } + else + { + message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token; + } + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr)); + } + + /*! + @param[out] dim an integer vector storing the ND array dimensions + @return whether reading ND array size vector is successful + */ + bool get_ubjson_ndarray_size(std::vector& dim) + { + std::pair size_and_type; + size_t dimlen = 0; + bool no_ndarray = true; + + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray))) + { + return false; + } + + if (size_and_type.first != npos) + { + if (size_and_type.second != 0) + { + if (size_and_type.second != 'N') + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second))) + { + return false; + } + dim.push_back(dimlen); + } + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray))) + { + return false; + } + dim.push_back(dimlen); + } + } + } + else + { + while (current != ']') + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current))) + { + return false; + } + dim.push_back(dimlen); + get_ignore_noop(); + } + } + return true; + } + + /*! + @param[out] result determined size + @param[in,out] is_ndarray for input, `true` means already inside an ndarray vector + or ndarray dimension is not allowed; `false` means ndarray + is allowed; for output, `true` means an ndarray is found; + is_ndarray can only return `true` when its initial value + is `false` + @param[in] prefix type marker if already read, otherwise set to 0 + + @return whether size determination completed + */ + bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0) + { + if (prefix == 0) + { + prefix = get_ignore_noop(); + } + + switch (prefix) + { + case 'U': + { + std::uint8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'i': + { + std::int8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + result = static_cast(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char + return true; + } + + case 'I': + { + std::int16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + result = static_cast(number); + return true; + } + + case 'l': + { + std::int32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + result = static_cast(number); + return true; + } + + case 'L': + { + std::int64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + if (!value_in_range_of(number)) + { + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + exception_message(input_format, "integer value overflow", "size"), nullptr)); + } + result = static_cast(number); + return true; + } + + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = conditional_static_cast(number); + return true; + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (!value_in_range_of(number)) + { + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + exception_message(input_format, "integer value overflow", "size"), nullptr)); + } + result = detail::conditional_static_cast(number); + return true; + } + + case '[': + { + if (input_format != input_format_t::bjdata) + { + break; + } + if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr)); + } + std::vector dim; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) + { + return false; + } + if (dim.size() == 1 || (dim.size() == 2 && dim.at(0) == 1)) // return normal array size if 1D row vector + { + result = dim.at(dim.size() - 1); + return true; + } + if (!dim.empty()) // if ndarray, convert to an object in JData annotated array format + { + for (auto i : dim) // test if any dimension in an ndarray is 0, if so, return a 1D empty container + { + if ( i == 0 ) + { + result = 0; + return true; + } + } + + string_t key = "_ArraySize_"; + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size()))) + { + return false; + } + result = 1; + for (auto i : dim) + { + result *= i; + if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type() + { + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); + } + if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast(i)))) + { + return false; + } + } + is_ndarray = true; + return sax->end_array(); + } + result = 0; + return true; + } + + default: + break; + } + auto last_token = get_token_string(); + std::string message; + + if (input_format != input_format_t::bjdata) + { + message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token; + } + else + { + message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token; + } + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr)); + } + + /*! + @brief determine the type and size for a container + + In the optimized UBJSON format, a type and a size can be provided to allow + for a more compact representation. + + @param[out] result pair of the size and the type + @param[in] inside_ndarray whether the parser is parsing an ND array dimensional vector + + @return whether pair creation completed + */ + bool get_ubjson_size_type(std::pair& result, bool inside_ndarray = false) + { + result.first = npos; // size + result.second = 0; // type + bool is_ndarray = false; + + get_ignore_noop(); + + if (current == '$') + { + result.second = get(); // must not ignore 'N', because 'N' maybe the type + if (input_format == input_format_t::bjdata + && JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second))) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr)); + } + + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type"))) + { + return false; + } + + get_ignore_noop(); + if (JSON_HEDLEY_UNLIKELY(current != '#')) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) + { + return false; + } + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr)); + } + + const bool is_error = get_ubjson_size_value(result.first, is_ndarray); + if (input_format == input_format_t::bjdata && is_ndarray) + { + if (inside_ndarray) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, + exception_message(input_format, "ndarray can not be recursive", "size"), nullptr)); + } + result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters + } + return is_error; + } + + if (current == '#') + { + const bool is_error = get_ubjson_size_value(result.first, is_ndarray); + if (input_format == input_format_t::bjdata && is_ndarray) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, + exception_message(input_format, "ndarray requires both type and size", "size"), nullptr)); + } + return is_error; + } + + return true; + } + + /*! + @param prefix the previously read or set type prefix + @return whether value creation completed + */ + bool get_ubjson_value(const char_int_type prefix) + { + switch (prefix) + { + case char_traits::eof(): // EOF + return unexpect_eof(input_format, "value"); + + case 'T': // true + return sax->boolean(true); + case 'F': // false + return sax->boolean(false); + + case 'Z': // null + return sax->null(); + + case 'U': + { + std::uint8_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'i': + { + std::int8_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'I': + { + std::int16_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'l': + { + std::int32_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'L': + { + std::int64_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'h': + { + if (input_format != input_format_t::bjdata) + { + break; + } + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const auto half = static_cast((byte2 << 8u) + byte1); + const double val = [&half] + { + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); + switch (exp) + { + case 0: + return std::ldexp(mant, -24); + case 31: + return (mant == 0) + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + default: + return std::ldexp(mant + 1024, exp - 25); + } + }(); + return sax->number_float((half & 0x8000u) != 0 + ? static_cast(-val) + : static_cast(val), ""); + } + + case 'd': + { + float number{}; + return get_number(input_format, number) && sax->number_float(static_cast(number), ""); + } + + case 'D': + { + double number{}; + return get_number(input_format, number) && sax->number_float(static_cast(number), ""); + } + + case 'H': + { + return get_ubjson_high_precision_number(); + } + + case 'C': // char + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char"))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(current > 127)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr)); + } + string_t s(1, static_cast(current)); + return sax->string(s); + } + + case 'S': // string + { + string_t s; + return get_ubjson_string(s) && sax->string(s); + } + + case '[': // array + return get_ubjson_array(); + + case '{': // object + return get_ubjson_object(); + + default: // anything else + break; + } + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr)); + } + + /*! + @return whether array creation completed + */ + bool get_ubjson_array() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + // if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata): + // {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]} + + if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) + { + size_and_type.second &= ~(static_cast(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker + auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t) + { + return p.first < t; + }); + string_t key = "_ArrayType_"; + if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr)); + } + + string_t type = it->second; // sax->string() takes a reference + if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type))) + { + return false; + } + + if (size_and_type.second == 'C') + { + size_and_type.second = 'U'; + } + + key = "_ArrayData_"; + if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) )) + { + return false; + } + + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + } + + return (sax->end_array() && sax->end_object()); + } + + if (size_and_type.first != npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + if (size_and_type.second != 'N') + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + } + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + { + return false; + } + + while (current != ']') + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false))) + { + return false; + } + get_ignore_noop(); + } + } + + return sax->end_array(); + } + + /*! + @return whether object creation completed + */ + bool get_ubjson_object() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + // do not accept ND-array size in objects in BJData + if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr)); + } + + string_t key; + if (size_and_type.first != npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + key.clear(); + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + key.clear(); + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + { + return false; + } + + while (current != '}') + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + get_ignore_noop(); + key.clear(); + } + } + + return sax->end_object(); + } + + // Note, no reader for UBJSON binary types is implemented because they do + // not exist + + bool get_ubjson_high_precision_number() + { + // get size of following number string + std::size_t size{}; + bool no_ndarray = true; + auto res = get_ubjson_size_value(size, no_ndarray); + if (JSON_HEDLEY_UNLIKELY(!res)) + { + return res; + } + + // get number string + std::vector number_vector; + for (std::size_t i = 0; i < size; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + number_vector.push_back(static_cast(current)); + } + + // parse number string + using ia_type = decltype(detail::input_adapter(number_vector)); + auto number_lexer = detail::lexer(detail::input_adapter(number_vector), false); + const auto result_number = number_lexer.scan(); + const auto number_string = number_lexer.get_token_string(); + const auto result_remainder = number_lexer.scan(); + + using token_type = typename detail::lexer_base::token_type; + + if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) + { + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, + exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); + } + + switch (result_number) + { + case token_type::value_integer: + return sax->number_integer(number_lexer.get_number_integer()); + case token_type::value_unsigned: + return sax->number_unsigned(number_lexer.get_number_unsigned()); + case token_type::value_float: + return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); + case token_type::uninitialized: + case token_type::literal_true: + case token_type::literal_false: + case token_type::literal_null: + case token_type::value_string: + case token_type::begin_array: + case token_type::begin_object: + case token_type::end_array: + case token_type::end_object: + case token_type::name_separator: + case token_type::value_separator: + case token_type::parse_error: + case token_type::end_of_input: + case token_type::literal_or_value: + default: + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, + exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); + } + } + + /////////////////////// + // Utility functions // + /////////////////////// + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `char_traits::eof()` in that case. + + @return character read from the input + */ + char_int_type get() + { + ++chars_read; + return current = ia.get_character(); + } + + /*! + @return character read from the input after ignoring all 'N' entries + */ + char_int_type get_ignore_noop() + { + do + { + get(); + } + while (current == 'N'); + + return current; + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[out] result number of type @a NumberType + + @return whether conversion completed + + @note This function needs to respect the system's endianness, because + bytes in CBOR, MessagePack, and UBJSON are stored in network order + (big endian) and therefore need reordering on little endian systems. + On the other hand, BSON and BJData use little endian and should reorder + on big endian systems. + */ + template + bool get_number(const input_format_t format, NumberType& result) + { + // step 1: read input into array with system's byte order + std::array vec{}; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) + { + return false; + } + + // reverse byte order prior to conversion if necessary + if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return true; + } + + /*! + @brief create a string by reading characters from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of characters to read + @param[out] result string created by reading @a len bytes + + @return whether string creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of string memory. + */ + template + bool get_string(const input_format_t format, + const NumberType len, + string_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + } + return success; + } + + /*! + @brief create a byte array by reading bytes from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of bytes to read + @param[out] result byte array created by reading @a len bytes + + @return whether byte array creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of memory. + */ + template + bool get_binary(const input_format_t format, + const NumberType len, + binary_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + } + return success; + } + + /*! + @param[in] format the current format (for diagnostics) + @param[in] context further context information (for diagnostics) + @return whether the last read character is not EOF + */ + JSON_HEDLEY_NON_NULL(3) + bool unexpect_eof(const input_format_t format, const char* context) const + { + if (JSON_HEDLEY_UNLIKELY(current == char_traits::eof())) + { + return sax->parse_error(chars_read, "", + parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); + } + return true; + } + + /*! + @return a string representation of the last read byte + */ + std::string get_token_string() const + { + std::array cr{{}}; + static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + return std::string{cr.data()}; + } + + /*! + @param[in] format the current format + @param[in] detail a detailed error message + @param[in] context further context information + @return a message string to use in the parse_error exceptions + */ + std::string exception_message(const input_format_t format, + const std::string& detail, + const std::string& context) const + { + std::string error_msg = "syntax error while parsing "; + + switch (format) + { + case input_format_t::cbor: + error_msg += "CBOR"; + break; + + case input_format_t::msgpack: + error_msg += "MessagePack"; + break; + + case input_format_t::ubjson: + error_msg += "UBJSON"; + break; + + case input_format_t::bson: + error_msg += "BSON"; + break; + + case input_format_t::bjdata: + error_msg += "BJData"; + break; + + case input_format_t::json: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + + return concat(error_msg, ' ', context, ": ", detail); + } + + private: + static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast(-1); + + /// input adapter + InputAdapterType ia; + + /// the current character + char_int_type current = char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianness + const bool is_little_endian = little_endianness(); + + /// input format + const input_format_t input_format = input_format_t::json; + + /// the SAX parser + json_sax_t* sax = nullptr; + + // excluded markers in bjdata optimized type +#define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \ + make_array('F', 'H', 'N', 'S', 'T', 'Z', '[', '{') + +#define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \ + make_array( \ + bjd_type{'C', "char"}, \ + bjd_type{'D', "double"}, \ + bjd_type{'I', "int16"}, \ + bjd_type{'L', "int64"}, \ + bjd_type{'M', "uint64"}, \ + bjd_type{'U', "uint8"}, \ + bjd_type{'d', "single"}, \ + bjd_type{'i', "int8"}, \ + bjd_type{'l', "int32"}, \ + bjd_type{'m', "uint32"}, \ + bjd_type{'u', "uint16"}) + + JSON_PRIVATE_UNLESS_TESTED: + // lookup tables + // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) + const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers = + JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_; + + using bjd_type = std::pair; + // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) + const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map = + JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_; + +#undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ +#undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr std::size_t binary_reader::npos; +#endif + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/input/input_adapters.hpp b/json/include/nlohmann/detail/input/input_adapters.hpp new file mode 100644 index 0000000..33fca3e --- /dev/null +++ b/json/include/nlohmann/detail/input/input_adapters.hpp @@ -0,0 +1,492 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // array +#include // size_t +#include // strlen +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +#ifndef JSON_NO_IO + #include // FILE * + #include // istream +#endif // JSON_NO_IO + +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// the supported input formats +enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata }; + +//////////////////// +// input adapters // +//////////////////// + +#ifndef JSON_NO_IO +/*! +Input adapter for stdio file access. This adapter read only 1 byte and do not use any + buffer. This adapter is a very low level adapter. +*/ +class file_input_adapter +{ + public: + using char_type = char; + + JSON_HEDLEY_NON_NULL(2) + explicit file_input_adapter(std::FILE* f) noexcept + : m_file(f) + { + JSON_ASSERT(m_file != nullptr); + } + + // make class move-only + file_input_adapter(const file_input_adapter&) = delete; + file_input_adapter(file_input_adapter&&) noexcept = default; + file_input_adapter& operator=(const file_input_adapter&) = delete; + file_input_adapter& operator=(file_input_adapter&&) = delete; + ~file_input_adapter() = default; + + std::char_traits::int_type get_character() noexcept + { + return std::fgetc(m_file); + } + + private: + /// the file pointer to read from + std::FILE* m_file; +}; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter +{ + public: + using char_type = char; + + ~input_stream_adapter() + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags, except eof + if (is != nullptr) + { + is->clear(is->rdstate() & std::ios::eofbit); + } + } + + explicit input_stream_adapter(std::istream& i) + : is(&i), sb(i.rdbuf()) + {} + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&&) = delete; + + input_stream_adapter(input_stream_adapter&& rhs) noexcept + : is(rhs.is), sb(rhs.sb) + { + rhs.is = nullptr; + rhs.sb = nullptr; + } + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, e.g. 0xFFFFFFFF. + std::char_traits::int_type get_character() + { + auto res = sb->sbumpc(); + // set eof manually, as we don't use the istream interface. + if (JSON_HEDLEY_UNLIKELY(res == std::char_traits::eof())) + { + is->clear(is->rdstate() | std::ios::eofbit); + } + return res; + } + + private: + /// the associated input stream + std::istream* is = nullptr; + std::streambuf* sb = nullptr; +}; +#endif // JSON_NO_IO + +// General-purpose iterator-based adapter. It might not be as fast as +// theoretically possible for some containers, but it is extremely versatile. +template +class iterator_input_adapter +{ + public: + using char_type = typename std::iterator_traits::value_type; + + iterator_input_adapter(IteratorType first, IteratorType last) + : current(std::move(first)), end(std::move(last)) + {} + + typename char_traits::int_type get_character() + { + if (JSON_HEDLEY_LIKELY(current != end)) + { + auto result = char_traits::to_int_type(*current); + std::advance(current, 1); + return result; + } + + return char_traits::eof(); + } + + private: + IteratorType current; + IteratorType end; + + template + friend struct wide_string_input_helper; + + bool empty() const + { + return current == end; + } +}; + +template +struct wide_string_input_helper; + +template +struct wide_string_input_helper +{ + // UTF-32 + static void fill_buffer(BaseInputAdapter& input, + std::array::int_type, 4>& utf8_bytes, + size_t& utf8_bytes_index, + size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (JSON_HEDLEY_UNLIKELY(input.empty())) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = input.get_character(); + + // UTF-32 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u) & 0x1Fu)); + utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 2; + } + else if (wc <= 0xFFFF) + { + utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u) & 0x0Fu)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 3; + } + else if (wc <= 0x10FFFF) + { + utf8_bytes[0] = static_cast::int_type>(0xF0u | ((static_cast(wc) >> 18u) & 0x07u)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 12u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[3] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 4; + } + else + { + // unknown character + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + } + } +}; + +template +struct wide_string_input_helper +{ + // UTF-16 + static void fill_buffer(BaseInputAdapter& input, + std::array::int_type, 4>& utf8_bytes, + size_t& utf8_bytes_index, + size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (JSON_HEDLEY_UNLIKELY(input.empty())) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = input.get_character(); + + // UTF-16 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u))); + utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 2; + } + else if (0xD800 > wc || wc >= 0xE000) + { + utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u))); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 3; + } + else + { + if (JSON_HEDLEY_UNLIKELY(!input.empty())) + { + const auto wc2 = static_cast(input.get_character()); + const auto charcode = 0x10000u + (((static_cast(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); + utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); + utf8_bytes[3] = static_cast::int_type>(0x80u | (charcode & 0x3Fu)); + utf8_bytes_filled = 4; + } + else + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + } + } + } +}; + +// Wraps another input adapter to convert wide character types into individual bytes. +template +class wide_string_input_adapter +{ + public: + using char_type = char; + + wide_string_input_adapter(BaseInputAdapter base) + : base_adapter(base) {} + + typename std::char_traits::int_type get_character() noexcept + { + // check if buffer needs to be filled + if (utf8_bytes_index == utf8_bytes_filled) + { + fill_buffer(); + + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index == 0); + } + + // use buffer + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); + return utf8_bytes[utf8_bytes_index++]; + } + + private: + BaseInputAdapter base_adapter; + + template + void fill_buffer() + { + wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); + } + + /// a buffer for UTF-8 bytes + std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; + + /// index to the utf8_codes array for the next valid byte + std::size_t utf8_bytes_index = 0; + /// number of valid bytes in the utf8_codes array + std::size_t utf8_bytes_filled = 0; +}; + +template +struct iterator_input_adapter_factory +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using adapter_type = iterator_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(std::move(first), std::move(last)); + } +}; + +template +struct is_iterator_of_multibyte +{ + using value_type = typename std::iterator_traits::value_type; + enum + { + value = sizeof(value_type) > 1 + }; +}; + +template +struct iterator_input_adapter_factory::value>> +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using base_adapter_type = iterator_input_adapter; + using adapter_type = wide_string_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(base_adapter_type(std::move(first), std::move(last))); + } +}; + +// General purpose iterator-based input +template +typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) +{ + using factory_type = iterator_input_adapter_factory; + return factory_type::create(first, last); +} + +// Convenience shorthand from container to iterator +// Enables ADL on begin(container) and end(container) +// Encloses the using declarations in namespace for not to leak them to outside scope + +namespace container_input_adapter_factory_impl +{ + +using std::begin; +using std::end; + +template +struct container_input_adapter_factory {}; + +template +struct container_input_adapter_factory< ContainerType, + void_t()), end(std::declval()))>> + { + using adapter_type = decltype(input_adapter(begin(std::declval()), end(std::declval()))); + + static adapter_type create(const ContainerType& container) +{ + return input_adapter(begin(container), end(container)); +} + }; + +} // namespace container_input_adapter_factory_impl + +template +typename container_input_adapter_factory_impl::container_input_adapter_factory::adapter_type input_adapter(const ContainerType& container) +{ + return container_input_adapter_factory_impl::container_input_adapter_factory::create(container); +} + +#ifndef JSON_NO_IO +// Special cases with fast paths +inline file_input_adapter input_adapter(std::FILE* file) +{ + return file_input_adapter(file); +} + +inline input_stream_adapter input_adapter(std::istream& stream) +{ + return input_stream_adapter(stream); +} + +inline input_stream_adapter input_adapter(std::istream&& stream) +{ + return input_stream_adapter(stream); +} +#endif // JSON_NO_IO + +using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); + +// Null-delimited strings, and the like. +template < typename CharT, + typename std::enable_if < + std::is_pointer::value&& + !std::is_array::value&& + std::is_integral::type>::value&& + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > +contiguous_bytes_input_adapter input_adapter(CharT b) +{ + auto length = std::strlen(reinterpret_cast(b)); + const auto* ptr = reinterpret_cast(b); + return input_adapter(ptr, ptr + length); +} + +template +auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +{ + return input_adapter(array, array + N); +} + +// This class only handles inputs of input_buffer_adapter type. +// It's required so that expressions like {ptr, len} can be implicitly cast +// to the correct adapter. +class span_input_adapter +{ + public: + template < typename CharT, + typename std::enable_if < + std::is_pointer::value&& + std::is_integral::type>::value&& + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > + span_input_adapter(CharT b, std::size_t l) + : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} + + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + span_input_adapter(IteratorType first, IteratorType last) + : ia(input_adapter(first, last)) {} + + contiguous_bytes_input_adapter&& get() + { + return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) + } + + private: + contiguous_bytes_input_adapter ia; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/input/json_sax.hpp b/json/include/nlohmann/detail/input/json_sax.hpp new file mode 100644 index 0000000..c772521 --- /dev/null +++ b/json/include/nlohmann/detail/input/json_sax.hpp @@ -0,0 +1,727 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include // string +#include // move +#include // vector + +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +/*! +@brief SAX interface + +This class describes the SAX interface used by @ref nlohmann::json::sax_parse. +Each function is called in different situations while the input is parsed. The +boolean return value informs the parser whether to continue processing the +input. +*/ +template +struct json_sax +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + /*! + @brief a null value was read + @return whether parsing should proceed + */ + virtual bool null() = 0; + + /*! + @brief a boolean value was read + @param[in] val boolean value + @return whether parsing should proceed + */ + virtual bool boolean(bool val) = 0; + + /*! + @brief an integer number was read + @param[in] val integer value + @return whether parsing should proceed + */ + virtual bool number_integer(number_integer_t val) = 0; + + /*! + @brief an unsigned integer number was read + @param[in] val unsigned integer value + @return whether parsing should proceed + */ + virtual bool number_unsigned(number_unsigned_t val) = 0; + + /*! + @brief a floating-point number was read + @param[in] val floating-point value + @param[in] s raw token value + @return whether parsing should proceed + */ + virtual bool number_float(number_float_t val, const string_t& s) = 0; + + /*! + @brief a string value was read + @param[in] val string value + @return whether parsing should proceed + @note It is safe to move the passed string value. + */ + virtual bool string(string_t& val) = 0; + + /*! + @brief a binary value was read + @param[in] val binary value + @return whether parsing should proceed + @note It is safe to move the passed binary value. + */ + virtual bool binary(binary_t& val) = 0; + + /*! + @brief the beginning of an object was read + @param[in] elements number of object elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_object(std::size_t elements) = 0; + + /*! + @brief an object key was read + @param[in] val object key + @return whether parsing should proceed + @note It is safe to move the passed string. + */ + virtual bool key(string_t& val) = 0; + + /*! + @brief the end of an object was read + @return whether parsing should proceed + */ + virtual bool end_object() = 0; + + /*! + @brief the beginning of an array was read + @param[in] elements number of array elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_array(std::size_t elements) = 0; + + /*! + @brief the end of an array was read + @return whether parsing should proceed + */ + virtual bool end_array() = 0; + + /*! + @brief a parse error occurred + @param[in] position the position in the input where the error occurs + @param[in] last_token the last read token + @param[in] ex an exception object describing the error + @return whether parsing should proceed (must return false) + */ + virtual bool parse_error(std::size_t position, + const std::string& last_token, + const detail::exception& ex) = 0; + + json_sax() = default; + json_sax(const json_sax&) = default; + json_sax(json_sax&&) noexcept = default; + json_sax& operator=(const json_sax&) = default; + json_sax& operator=(json_sax&&) noexcept = default; + virtual ~json_sax() = default; +}; + +namespace detail +{ +/*! +@brief SAX implementation to create a JSON value from SAX events + +This class implements the @ref json_sax interface and processes the SAX events +to create a JSON value which makes it basically a DOM parser. The structure or +hierarchy of the JSON value is managed by the stack `ref_stack` which contains +a pointer to the respective array or object for each recursion depth. + +After successful parsing, the value that is passed by reference to the +constructor contains the parsed value. + +@tparam BasicJsonType the JSON type +*/ +template +class json_sax_dom_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + /*! + @param[in,out] r reference to a JSON value that is manipulated while + parsing + @param[in] allow_exceptions_ whether parse errors yield exceptions + */ + explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) + : root(r), allow_exceptions(allow_exceptions_) + {} + + // make class move-only + json_sax_dom_parser(const json_sax_dom_parser&) = delete; + json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; + json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~json_sax_dom_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); + + if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + } + + return true; + } + + bool key(string_t& val) + { + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(ref_stack.back()->is_object()); + + // add null at given key and store the reference for later + object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val)); + return true; + } + + bool end_object() + { + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(ref_stack.back()->is_object()); + + ref_stack.back()->set_parents(); + ref_stack.pop_back(); + return true; + } + + bool start_array(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); + + if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + } + + return true; + } + + bool end_array() + { + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(ref_stack.back()->is_array()); + + ref_stack.back()->set_parents(); + ref_stack.pop_back(); + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + /*! + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + */ + template + JSON_HEDLEY_RETURNS_NON_NULL + BasicJsonType* handle_value(Value&& v) + { + if (ref_stack.empty()) + { + root = BasicJsonType(std::forward(v)); + return &root; + } + + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_data.m_value.array->emplace_back(std::forward(v)); + return &(ref_stack.back()->m_data.m_value.array->back()); + } + + JSON_ASSERT(ref_stack.back()->is_object()); + JSON_ASSERT(object_element); + *object_element = BasicJsonType(std::forward(v)); + return object_element; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; + +template +class json_sax_dom_callback_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using parser_callback_t = typename BasicJsonType::parser_callback_t; + using parse_event_t = typename BasicJsonType::parse_event_t; + + json_sax_dom_callback_parser(BasicJsonType& r, + const parser_callback_t cb, + const bool allow_exceptions_ = true) + : root(r), callback(cb), allow_exceptions(allow_exceptions_) + { + keep_stack.push_back(true); + } + + // make class move-only + json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~json_sax_dom_callback_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + // check callback for object start + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::object_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::object, true); + ref_stack.push_back(val.second); + + // check object limit + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + } + + return true; + } + + bool key(string_t& val) + { + BasicJsonType k = BasicJsonType(val); + + // check callback for key + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); + key_keep_stack.push_back(keep); + + // add discarded value at given key and store the reference for later + if (keep && ref_stack.back()) + { + object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded); + } + + return true; + } + + bool end_object() + { + if (ref_stack.back()) + { + if (!callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) + { + // discard object + *ref_stack.back() = discarded; + } + else + { + ref_stack.back()->set_parents(); + } + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) + { + // remove discarded value + for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) + { + if (it->is_discarded()) + { + ref_stack.back()->erase(it); + break; + } + } + } + + return true; + } + + bool start_array(std::size_t len) + { + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::array_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::array, true); + ref_stack.push_back(val.second); + + // check array limit + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + } + + return true; + } + + bool end_array() + { + bool keep = true; + + if (ref_stack.back()) + { + keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); + if (keep) + { + ref_stack.back()->set_parents(); + } + else + { + // discard array + *ref_stack.back() = discarded; + } + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + // remove discarded value + if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) + { + ref_stack.back()->m_data.m_value.array->pop_back(); + } + + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + /*! + @param[in] v value to add to the JSON value we build during parsing + @param[in] skip_callback whether we should skip calling the callback + function; this is required after start_array() and + start_object() SAX events, because otherwise we would call the + callback function with an empty array or object, respectively. + + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + + @return pair of boolean (whether value should be kept) and pointer (to the + passed value in the ref_stack hierarchy; nullptr if not kept) + */ + template + std::pair handle_value(Value&& v, const bool skip_callback = false) + { + JSON_ASSERT(!keep_stack.empty()); + + // do not handle this value if we know it would be added to a discarded + // container + if (!keep_stack.back()) + { + return {false, nullptr}; + } + + // create value + auto value = BasicJsonType(std::forward(v)); + + // check callback + const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); + + // do not handle this value if we just learnt it shall be discarded + if (!keep) + { + return {false, nullptr}; + } + + if (ref_stack.empty()) + { + root = std::move(value); + return {true, & root}; + } + + // skip this value if we already decided to skip the parent + // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) + if (!ref_stack.back()) + { + return {false, nullptr}; + } + + // we now only expect arrays and objects + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + // array + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value)); + return {true, & (ref_stack.back()->m_data.m_value.array->back())}; + } + + // object + JSON_ASSERT(ref_stack.back()->is_object()); + // check if we should store an element for the current key + JSON_ASSERT(!key_keep_stack.empty()); + const bool store_element = key_keep_stack.back(); + key_keep_stack.pop_back(); + + if (!store_element) + { + return {false, nullptr}; + } + + JSON_ASSERT(object_element); + *object_element = std::move(value); + return {true, object_element}; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// stack to manage which values to keep + std::vector keep_stack {}; + /// stack to manage which object keys to keep + std::vector key_keep_stack {}; + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// callback function + const parser_callback_t callback = nullptr; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; + /// a discarded value for the callback + BasicJsonType discarded = BasicJsonType::value_t::discarded; +}; + +template +class json_sax_acceptor +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + bool null() + { + return true; + } + + bool boolean(bool /*unused*/) + { + return true; + } + + bool number_integer(number_integer_t /*unused*/) + { + return true; + } + + bool number_unsigned(number_unsigned_t /*unused*/) + { + return true; + } + + bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) + { + return true; + } + + bool string(string_t& /*unused*/) + { + return true; + } + + bool binary(binary_t& /*unused*/) + { + return true; + } + + bool start_object(std::size_t /*unused*/ = static_cast(-1)) + { + return true; + } + + bool key(string_t& /*unused*/) + { + return true; + } + + bool end_object() + { + return true; + } + + bool start_array(std::size_t /*unused*/ = static_cast(-1)) + { + return true; + } + + bool end_array() + { + return true; + } + + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) + { + return false; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/input/lexer.hpp b/json/include/nlohmann/detail/input/lexer.hpp new file mode 100644 index 0000000..4b3bf77 --- /dev/null +++ b/json/include/nlohmann/detail/input/lexer.hpp @@ -0,0 +1,1633 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // array +#include // localeconv +#include // size_t +#include // snprintf +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // char_traits, string +#include // move +#include // vector + +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/////////// +// lexer // +/////////// + +template +class lexer_base +{ + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + JSON_HEDLEY_RETURNS_NON_NULL + JSON_HEDLEY_CONST + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case token_type::value_unsigned: + case token_type::value_integer: + case token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + // LCOV_EXCL_START + default: // catch non-enum values + return "unknown token"; + // LCOV_EXCL_STOP + } + } +}; +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer : public lexer_base +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using char_type = typename InputAdapterType::char_type; + using char_int_type = typename char_traits::int_type; + + public: + using token_type = typename lexer_base::token_type; + + explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept + : ia(std::move(adapter)) + , ignore_comments(ignore_comments_) + , decimal_point_char(static_cast(get_decimal_point())) + {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + lexer& operator=(lexer&) = delete; + lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~lexer() = default; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + JSON_HEDLEY_PURE + static char get_decimal_point() noexcept + { + const auto* loc = localeconv(); + JSON_ASSERT(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + JSON_ASSERT(current == 'u'); + int codepoint = 0; + + const auto factors = { 12u, 8u, 4u, 0u }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' && current <= '9') + { + codepoint += static_cast((static_cast(current) - 0x30u) << factor); + } + else if (current >= 'A' && current <= 'F') + { + codepoint += static_cast((static_cast(current) - 0x37u) << factor); + } + else if (current >= 'a' && current <= 'f') + { + codepoint += static_cast((static_cast(current) - 0x57u) << factor); + } + else + { + return -1; + } + } + + JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) // NOLINT(bugprone-inc-dec-in-conditions) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 8259. While + scanning, bytes are escaped and copied into buffer token_buffer. Then the + function returns successfully, token_buffer is *not* null-terminated (as it + may contain \0 bytes), and token_buffer.size() is the number of bytes in the + string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset token_buffer (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + JSON_ASSERT(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = static_cast( + // high surrogate occupies the most significant 22 bits + (static_cast(codepoint1) << 10u) + // low surrogate occupies the least significant 15 bits + + static_cast(codepoint2) + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result, so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00u); + } + else + { + error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(static_cast(codepoint)); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(static_cast(0xC0u | (static_cast(codepoint) >> 6u))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(static_cast(0xE0u | (static_cast(codepoint) >> 12u))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(static_cast(0xF0u | (static_cast(codepoint) >> 18u))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 12u) & 0x3Fu))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + { + error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; + return token_type::parse_error; + } + + case 0x01: + { + error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; + return token_type::parse_error; + } + + case 0x02: + { + error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; + return token_type::parse_error; + } + + case 0x03: + { + error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; + return token_type::parse_error; + } + + case 0x04: + { + error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; + return token_type::parse_error; + } + + case 0x05: + { + error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; + return token_type::parse_error; + } + + case 0x06: + { + error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; + return token_type::parse_error; + } + + case 0x07: + { + error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; + return token_type::parse_error; + } + + case 0x08: + { + error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; + return token_type::parse_error; + } + + case 0x09: + { + error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; + return token_type::parse_error; + } + + case 0x0A: + { + error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; + return token_type::parse_error; + } + + case 0x0B: + { + error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; + return token_type::parse_error; + } + + case 0x0C: + { + error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; + return token_type::parse_error; + } + + case 0x0D: + { + error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; + return token_type::parse_error; + } + + case 0x0E: + { + error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; + return token_type::parse_error; + } + + case 0x0F: + { + error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; + return token_type::parse_error; + } + + case 0x10: + { + error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; + return token_type::parse_error; + } + + case 0x11: + { + error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; + return token_type::parse_error; + } + + case 0x12: + { + error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; + return token_type::parse_error; + } + + case 0x13: + { + error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; + return token_type::parse_error; + } + + case 0x14: + { + error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; + return token_type::parse_error; + } + + case 0x15: + { + error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; + return token_type::parse_error; + } + + case 0x16: + { + error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; + return token_type::parse_error; + } + + case 0x17: + { + error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; + return token_type::parse_error; + } + + case 0x18: + { + error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; + return token_type::parse_error; + } + + case 0x19: + { + error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; + return token_type::parse_error; + } + + case 0x1A: + { + error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; + return token_type::parse_error; + } + + case 0x1B: + { + error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; + return token_type::parse_error; + } + + case 0x1C: + { + error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; + return token_type::parse_error; + } + + case 0x1D: + { + error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; + return token_type::parse_error; + } + + case 0x1E: + { + error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; + return token_type::parse_error; + } + + case 0x1F: + { + error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + /*! + * @brief scan a comment + * @return whether comment could be scanned successfully + */ + bool scan_comment() + { + switch (get()) + { + // single-line comments skip input until a newline or EOF is read + case '/': + { + while (true) + { + switch (get()) + { + case '\n': + case '\r': + case char_traits::eof(): + case '\0': + return true; + + default: + break; + } + } + } + + // multi-line comments skip input until */ is read + case '*': + { + while (true) + { + switch (get()) + { + case char_traits::eof(): + case '\0': + { + error_message = "invalid comment; missing closing '*/'"; + return false; + } + + case '*': + { + switch (get()) + { + case '/': + return true; + + default: + { + unget(); + continue; + } + } + } + + default: + continue; + } + } + } + + // unexpected character after reading '/' + default: + { + error_message = "invalid comment; expecting '/' or '*' after '/'"; + return false; + } + } + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 8259. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 8259. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | decimal2 | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in token_buffer. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() // lgtm [cpp/use-of-goto] + { + // reset token_buffer to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + // all other characters are rejected outside scan_number() + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(token_buffer.data(), &endptr, 10); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(token_buffer.data(), &endptr, 10); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, token_buffer.data(), &endptr); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + JSON_HEDLEY_NON_NULL(2) + token_type scan_literal(const char_type* literal_text, const std::size_t length, + token_type return_type) + { + JSON_ASSERT(char_traits::to_char_type(current) == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_HEDLEY_UNLIKELY(char_traits::to_char_type(get()) != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset token_buffer; current character is beginning of token + void reset() noexcept + { + token_buffer.clear(); + token_string.clear(); + token_string.push_back(char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + char_int_type get() + { + ++position.chars_read_total; + ++position.chars_read_current_line; + + if (next_unget) + { + // just reset the next_unget variable and work with current + next_unget = false; + } + else + { + current = ia.get_character(); + } + + if (JSON_HEDLEY_LIKELY(current != char_traits::eof())) + { + token_string.push_back(char_traits::to_char_type(current)); + } + + if (current == '\n') + { + ++position.lines_read; + position.chars_read_current_line = 0; + } + + return current; + } + + /*! + @brief unget current character (read it again on next get) + + We implement unget by setting variable next_unget to true. The input is not + changed - we just simulate ungetting by modifying chars_read_total, + chars_read_current_line, and token_string. The next call to get() will + behave as if the unget character is read again. + */ + void unget() + { + next_unget = true; + + --position.chars_read_total; + + // in case we "unget" a newline, we have to also decrement the lines_read + if (position.chars_read_current_line == 0) + { + if (position.lines_read > 0) + { + --position.lines_read; + } + } + else + { + --position.chars_read_current_line; + } + + if (JSON_HEDLEY_LIKELY(current != char_traits::eof())) + { + JSON_ASSERT(!token_string.empty()); + token_string.pop_back(); + } + } + + /// add a character to token_buffer + void add(char_int_type c) + { + token_buffer.push_back(static_cast(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + string_t& get_string() + { + return token_buffer; + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr position_t get_position() const noexcept + { + return position; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if (static_cast(c) <= '\x1F') + { + // escape control characters + std::array cs{{}}; + static_cast((std::snprintf)(cs.data(), cs.size(), "", static_cast(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + result += cs.data(); + } + else + { + // add character as is + result.push_back(static_cast(c)); + } + } + + return result; + } + + /// return syntax error message + JSON_HEDLEY_RETURNS_NON_NULL + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + /*! + @brief skip the UTF-8 byte order mark + @return true iff there is no BOM or the correct BOM has been skipped + */ + bool skip_bom() + { + if (get() == 0xEF) + { + // check if we completely parse the BOM + return get() == 0xBB && get() == 0xBF; + } + + // the first character is not the beginning of the BOM; unget it to + // process is later + unget(); + return true; + } + + void skip_whitespace() + { + do + { + get(); + } + while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); + } + + token_type scan() + { + // initially, skip the BOM + if (position.chars_read_total == 0 && !skip_bom()) + { + error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; + return token_type::parse_error; + } + + // read next character and ignore whitespace + skip_whitespace(); + + // ignore comments + while (ignore_comments && current == '/') + { + if (!scan_comment()) + { + return token_type::parse_error; + } + + // skip following whitespace + skip_whitespace(); + } + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + { + std::array true_literal = {{static_cast('t'), static_cast('r'), static_cast('u'), static_cast('e')}}; + return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); + } + case 'f': + { + std::array false_literal = {{static_cast('f'), static_cast('a'), static_cast('l'), static_cast('s'), static_cast('e')}}; + return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); + } + case 'n': + { + std::array null_literal = {{static_cast('n'), static_cast('u'), static_cast('l'), static_cast('l')}}; + return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); + } + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + InputAdapterType ia; + + /// whether comments should be ignored (true) or signaled as errors (false) + const bool ignore_comments = false; + + /// the current character + char_int_type current = char_traits::eof(); + + /// whether the next get() call should just return current + bool next_unget = false; + + /// the start position of the current token + position_t position {}; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + string_t token_buffer {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char_int_type decimal_point_char = '.'; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/input/parser.hpp b/json/include/nlohmann/detail/input/parser.hpp new file mode 100644 index 0000000..bdf85ba --- /dev/null +++ b/json/include/nlohmann/detail/input/parser.hpp @@ -0,0 +1,519 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move +#include // vector + +#include +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +//////////// +// parser // +//////////// + +enum class parse_event_t : std::uint8_t +{ + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value +}; + +template +using parser_callback_t = + std::function; + +/*! +@brief syntax analysis + +This class implements a recursive descent parser. +*/ +template +class parser +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using lexer_t = lexer; + using token_type = typename lexer_t::token_type; + + public: + /// a parser reading from an input adapter + explicit parser(InputAdapterType&& adapter, + const parser_callback_t cb = nullptr, + const bool allow_exceptions_ = true, + const bool skip_comments = false) + : callback(cb) + , m_lexer(std::move(adapter), skip_comments) + , allow_exceptions(allow_exceptions_) + { + // read first token + get_token(); + } + + /*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse(const bool strict, BasicJsonType& result) + { + if (callback) + { + json_sax_dom_callback_parser sdp(result, callback, allow_exceptions); + sax_parse_internal(&sdp); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"), nullptr)); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + + // set top-level value to null if it was discarded by the callback + // function + if (result.is_discarded()) + { + result = nullptr; + } + } + else + { + json_sax_dom_parser sdp(result, allow_exceptions); + sax_parse_internal(&sdp); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + } + + result.assert_invariant(); + } + + /*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ + bool accept(const bool strict = true) + { + json_sax_acceptor sax_acceptor; + return sax_parse(&sax_acceptor, strict); + } + + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse(SAX* sax, const bool strict = true) + { + (void)detail::is_sax_static_asserts {}; + const bool result = sax_parse_internal(sax); + + // strict mode: next byte must be EOF + if (result && strict && (get_token() != token_type::end_of_input)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); + } + + return result; + } + + private: + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse_internal(SAX* sax) + { + // stack to remember the hierarchy of structured values we are parsing + // true = array; false = object + std::vector states; + // value to avoid a goto (see comment where set to true) + bool skip_to_state_evaluation = false; + + while (true) + { + if (!skip_to_state_evaluation) + { + // invariant: get_token() was called before each iteration + switch (last_token) + { + case token_type::begin_object: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + { + return false; + } + + // closing } -> we are done + if (get_token() == token_type::end_object) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + break; + } + + // parse key + if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); + } + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); + } + + // remember we are now inside an object + states.push_back(false); + + // parse values + get_token(); + continue; + } + + case token_type::begin_array: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + { + return false; + } + + // closing ] -> we are done + if (get_token() == token_type::end_array) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + break; + } + + // remember we are now inside an array + states.push_back(true); + + // parse values (no need to call get_token) + continue; + } + + case token_type::value_float: + { + const auto res = m_lexer.get_number_float(); + + if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr)); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) + { + return false; + } + + break; + } + + case token_type::literal_false: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) + { + return false; + } + break; + } + + case token_type::literal_null: + { + if (JSON_HEDLEY_UNLIKELY(!sax->null())) + { + return false; + } + break; + } + + case token_type::literal_true: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) + { + return false; + } + break; + } + + case token_type::value_integer: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) + { + return false; + } + break; + } + + case token_type::value_string: + { + if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) + { + return false; + } + break; + } + + case token_type::value_unsigned: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) + { + return false; + } + break; + } + + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr)); + } + case token_type::end_of_input: + { + if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr)); + } + case token_type::uninitialized: + case token_type::end_array: + case token_type::end_object: + case token_type::name_separator: + case token_type::value_separator: + case token_type::literal_or_value: + default: // the last token was unexpected + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr)); + } + } + } + else + { + skip_to_state_evaluation = false; + } + + // we reached this line after we successfully parsed a value + if (states.empty()) + { + // empty stack: we reached the end of the hierarchy: done + return true; + } + + if (states.back()) // array + { + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse a new value + get_token(); + continue; + } + + // closing ] + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + + // We are done with this array. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr)); + } + + // states.back() is false -> object + + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse key + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); + } + + // parse values + get_token(); + continue; + } + + // closing } + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + + // We are done with this object. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr)); + } + } + + /// get next token from lexer + token_type get_token() + { + return last_token = m_lexer.scan(); + } + + std::string exception_message(const token_type expected, const std::string& context) + { + std::string error_msg = "syntax error "; + + if (!context.empty()) + { + error_msg += concat("while parsing ", context, ' '); + } + + error_msg += "- "; + + if (last_token == token_type::parse_error) + { + error_msg += concat(m_lexer.get_error_message(), "; last read: '", + m_lexer.get_token_string(), '\''); + } + else + { + error_msg += concat("unexpected ", lexer_t::token_type_name(last_token)); + } + + if (expected != token_type::uninitialized) + { + error_msg += concat("; expected ", lexer_t::token_type_name(expected)); + } + + return error_msg; + } + + private: + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + token_type last_token = token_type::uninitialized; + /// the lexer + lexer_t m_lexer; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/input/position_t.hpp b/json/include/nlohmann/detail/input/position_t.hpp new file mode 100644 index 0000000..8ac7c78 --- /dev/null +++ b/json/include/nlohmann/detail/input/position_t.hpp @@ -0,0 +1,37 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // size_t + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/iterators/internal_iterator.hpp b/json/include/nlohmann/detail/iterators/internal_iterator.hpp new file mode 100644 index 0000000..2991ee6 --- /dev/null +++ b/json/include/nlohmann/detail/iterators/internal_iterator.hpp @@ -0,0 +1,35 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/iterators/iter_impl.hpp b/json/include/nlohmann/detail/iterators/iter_impl.hpp new file mode 100644 index 0000000..4447091 --- /dev/null +++ b/json/include/nlohmann/detail/iterators/iter_impl.hpp @@ -0,0 +1,751 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// forward declare, to be able to friend it later on +template class iteration_proxy; +template class iteration_proxy_value; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) +{ + /// the iterator with BasicJsonType of different const-ness + using other_iter_impl = iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; + /// allow basic_json to access private members + friend other_iter_impl; + friend BasicJsonType; + friend iteration_proxy; + friend iteration_proxy_value; + + using object_t = typename BasicJsonType::object_t; + using array_t = typename BasicJsonType::array_t; + // make sure BasicJsonType is basic_json or const basic_json + static_assert(is_basic_json::type>::value, + "iter_impl only accepts (const) basic_json"); + // superficial check for the LegacyBidirectionalIterator named requirement + static_assert(std::is_base_of::value + && std::is_base_of::iterator_category>::value, + "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement."); + + public: + /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. + /// The C++ Standard has never required user-defined iterators to derive from std::iterator. + /// A user-defined iterator should provide publicly accessible typedefs named + /// iterator_category, value_type, difference_type, pointer, and reference. + /// Note that value_type is required to be non-const, even for constant iterators. + using iterator_category = std::bidirectional_iterator_tag; + + /// the type of the values when the iterator is dereferenced + using value_type = typename BasicJsonType::value_type; + /// a type to represent differences between iterators + using difference_type = typename BasicJsonType::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename BasicJsonType::const_pointer, + typename BasicJsonType::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = + typename std::conditional::value, + typename BasicJsonType::const_reference, + typename BasicJsonType::reference>::type; + + iter_impl() = default; + ~iter_impl() = default; + iter_impl(iter_impl&&) noexcept = default; + iter_impl& operator=(iter_impl&&) noexcept = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept : m_object(object) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + + /*! + @brief const copy constructor + @param[in] other const iterator to copy from + @note This copy constructor had to be defined explicitly to circumvent a bug + occurring on msvc v19.0 compiler (VS 2015) debug build. For more + information refer to: https://github.com/nlohmann/json/issues/1608 + */ + iter_impl(const iter_impl& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl& other) noexcept + { + if (&other != this) + { + m_object = other.m_object; + m_it = other.m_it; + } + return *this; + } + + /*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl::type>& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl::type>& other) noexcept // NOLINT(cert-oop54-cpp) + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + JSON_PRIVATE_UNLESS_TESTED: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_data.m_value.object->begin(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_data.m_value.array->begin(); + break; + } + + case value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_data.m_value.object->end(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_data.m_value.array->end(); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); + return m_it.object_iterator->second; + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); + return *m_it.array_iterator; + } + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); + return &*m_it.array_iterator; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > + bool operator==(const IterImpl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); + } + + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + return (m_it.object_iterator == other.m_it.object_iterator); + + case value_t::array: + return (m_it.array_iterator == other.m_it.array_iterator); + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > + bool operator!=(const IterImpl& other) const + { + return !operator==(other); + } + + /*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); + } + + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object)); + + case value_t::array: + return (m_it.array_iterator < other.m_it.array_iterator); + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<=(const iter_impl& other) const + { + return !other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>(const iter_impl& other) const + { + return !operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>=(const iter_impl& other) const + { + return !operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); + + case value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + friend iter_impl operator+(difference_type i, const iter_impl& it) + { + auto result = it; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); + + case value_t::array: + return m_it.array_iterator - other.m_it.array_iterator; + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object)); + + case value_t::array: + return *std::next(m_it.array_iterator, n); + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n)) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + const typename object_t::key_type& key() const + { + JSON_ASSERT(m_object != nullptr); + + if (JSON_HEDLEY_LIKELY(m_object->is_object())) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object)); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + JSON_PRIVATE_UNLESS_TESTED: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator::type> m_it {}; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/iterators/iteration_proxy.hpp b/json/include/nlohmann/detail/iterators/iteration_proxy.hpp new file mode 100644 index 0000000..76293de --- /dev/null +++ b/json/include/nlohmann/detail/iterators/iteration_proxy.hpp @@ -0,0 +1,242 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // size_t +#include // input_iterator_tag +#include // string, to_string +#include // tuple_size, get, tuple_element +#include // move + +#if JSON_HAS_RANGES + #include // enable_borrowed_range +#endif + +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +void int_to_string( string_type& target, std::size_t value ) +{ + // For ADL + using std::to_string; + target = to_string(value); +} +template class iteration_proxy_value +{ + public: + using difference_type = std::ptrdiff_t; + using value_type = iteration_proxy_value; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::input_iterator_tag; + using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; + + private: + /// the iterator + IteratorType anchor{}; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + /// last stringified array index + mutable std::size_t array_index_last = 0; + /// a string representation of the array index + mutable string_type array_index_str = "0"; + /// an empty string (to return a reference for primitive values) + string_type empty_str{}; + + public: + explicit iteration_proxy_value() = default; + explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0) + noexcept(std::is_nothrow_move_constructible::value + && std::is_nothrow_default_constructible::value) + : anchor(std::move(it)) + , array_index(array_index_) + {} + + iteration_proxy_value(iteration_proxy_value const&) = default; + iteration_proxy_value& operator=(iteration_proxy_value const&) = default; + // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions + iteration_proxy_value(iteration_proxy_value&&) + noexcept(std::is_nothrow_move_constructible::value + && std::is_nothrow_move_constructible::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations) + iteration_proxy_value& operator=(iteration_proxy_value&&) + noexcept(std::is_nothrow_move_assignable::value + && std::is_nothrow_move_assignable::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations) + ~iteration_proxy_value() = default; + + /// dereference operator (needed for range-based for) + const iteration_proxy_value& operator*() const + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_value& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp) + { + auto tmp = iteration_proxy_value(anchor, array_index); + ++anchor; + ++array_index; + return tmp; + } + + /// equality operator (needed for InputIterator) + bool operator==(const iteration_proxy_value& o) const + { + return anchor == o.anchor; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_value& o) const + { + return anchor != o.anchor; + } + + /// return key of the iterator + const string_type& key() const + { + JSON_ASSERT(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + if (array_index != array_index_last) + { + int_to_string( array_index_str, array_index ); + array_index_last = array_index; + } + return array_index_str; + } + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return empty_str; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } +}; + +/// proxy class for the items() function +template class iteration_proxy +{ + private: + /// the container to iterate + typename IteratorType::pointer container = nullptr; + + public: + explicit iteration_proxy() = default; + + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) noexcept + : container(&cont) {} + + iteration_proxy(iteration_proxy const&) = default; + iteration_proxy& operator=(iteration_proxy const&) = default; + iteration_proxy(iteration_proxy&&) noexcept = default; + iteration_proxy& operator=(iteration_proxy&&) noexcept = default; + ~iteration_proxy() = default; + + /// return iterator begin (needed for range-based for) + iteration_proxy_value begin() const noexcept + { + return iteration_proxy_value(container->begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_value end() const noexcept + { + return iteration_proxy_value(container->end()); + } +}; + +// Structured Bindings Support +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +template = 0> +auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) +{ + return i.key(); +} +// Structured Bindings Support +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +template = 0> +auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) +{ + return i.value(); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// The Addition to the STD Namespace is required to add +// Structured Bindings Support to the iteration_proxy_value class +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +namespace std +{ + +#if defined(__clang__) + // Fix: https://github.com/nlohmann/json/issues/1401 + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wmismatched-tags" +#endif +template +class tuple_size<::nlohmann::detail::iteration_proxy_value> // NOLINT(cert-dcl58-cpp) + : public std::integral_constant {}; + +template +class tuple_element> // NOLINT(cert-dcl58-cpp) +{ + public: + using type = decltype( + get(std::declval < + ::nlohmann::detail::iteration_proxy_value> ())); +}; +#if defined(__clang__) + #pragma clang diagnostic pop +#endif + +} // namespace std + +#if JSON_HAS_RANGES + template + inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy> = true; +#endif diff --git a/json/include/nlohmann/detail/iterators/iterator_traits.hpp b/json/include/nlohmann/detail/iterators/iterator_traits.hpp new file mode 100644 index 0000000..84cc27a --- /dev/null +++ b/json/include/nlohmann/detail/iterators/iterator_traits.hpp @@ -0,0 +1,61 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // random_access_iterator_tag + +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/iterators/json_reverse_iterator.hpp b/json/include/nlohmann/detail/iterators/json_reverse_iterator.hpp new file mode 100644 index 0000000..006d549 --- /dev/null +++ b/json/include/nlohmann/detail/iterators/json_reverse_iterator.hpp @@ -0,0 +1,130 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ + public: + using difference_type = std::ptrdiff_t; + /// shortcut to the reverse iterator adapter + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) {} + + /// create reverse iterator from base class + explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + + /// post-increment (it++) + json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp) + { + return static_cast(base_iterator::operator++(1)); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + return static_cast(base_iterator::operator++()); + } + + /// post-decrement (it--) + json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp) + { + return static_cast(base_iterator::operator--(1)); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + return static_cast(base_iterator::operator--()); + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + return static_cast(base_iterator::operator+=(i)); + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + return static_cast(base_iterator::operator+(i)); + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + return static_cast(base_iterator::operator-(i)); + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return base_iterator(*this) - base_iterator(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + auto key() const -> decltype(std::declval().key()) + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/iterators/primitive_iterator.hpp b/json/include/nlohmann/detail/iterators/primitive_iterator.hpp new file mode 100644 index 0000000..0b6e849 --- /dev/null +++ b/json/include/nlohmann/detail/iterators/primitive_iterator.hpp @@ -0,0 +1,132 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // ptrdiff_t +#include // numeric_limits + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + private: + using difference_type = std::ptrdiff_t; + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + JSON_PRIVATE_UNLESS_TESTED: + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); + + public: + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type n) noexcept + { + auto result = *this; + result += n; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + primitive_iterator_t& operator++() noexcept + { + ++m_it; + return *this; + } + + primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + ++m_it; + return result; + } + + primitive_iterator_t& operator--() noexcept + { + --m_it; + return *this; + } + + primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + --m_it; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) noexcept + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) noexcept + { + m_it -= n; + return *this; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/json_custom_base_class.hpp b/json/include/nlohmann/detail/json_custom_base_class.hpp new file mode 100644 index 0000000..d1e2916 --- /dev/null +++ b/json/include/nlohmann/detail/json_custom_base_class.hpp @@ -0,0 +1,39 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // conditional, is_same + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief Default base class of the @ref basic_json class. + +So that the correct implementations of the copy / move ctors / assign operators +of @ref basic_json do not require complex case distinctions +(no base class / custom base class used as customization point), +@ref basic_json always has a base class. +By default, this class is used because it is empty and thus has no effect +on the behavior of @ref basic_json. +*/ +struct json_default_base {}; + +template +using json_base_class = typename std::conditional < + std::is_same::value, + json_default_base, + T + >::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/json_pointer.hpp b/json/include/nlohmann/detail/json_pointer.hpp new file mode 100644 index 0000000..4fdcd9a --- /dev/null +++ b/json/include/nlohmann/detail/json_pointer.hpp @@ -0,0 +1,988 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // all_of +#include // isdigit +#include // errno, ERANGE +#include // strtoull +#ifndef JSON_NO_IO + #include // ostream +#endif // JSON_NO_IO +#include // max +#include // accumulate +#include // string +#include // move +#include // vector + +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document +/// @sa https://json.nlohmann.me/api/json_pointer/ +template +class json_pointer +{ + // allow basic_json to access private members + NLOHMANN_BASIC_JSON_TPL_DECLARATION + friend class basic_json; + + template + friend class json_pointer; + + template + struct string_t_helper + { + using type = T; + }; + + NLOHMANN_BASIC_JSON_TPL_DECLARATION + struct string_t_helper + { + using type = StringType; + }; + + public: + // for backwards compatibility accept BasicJsonType + using string_t = typename string_t_helper::type; + + /// @brief create JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/ + explicit json_pointer(const string_t& s = "") + : reference_tokens(split(s)) + {} + + /// @brief return a string representation of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/to_string/ + string_t to_string() const + { + return std::accumulate(reference_tokens.begin(), reference_tokens.end(), + string_t{}, + [](const string_t& a, const string_t& b) + { + return detail::concat(a, '/', detail::escape(b)); + }); + } + + /// @brief return a string representation of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/ + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string()) + operator string_t() const + { + return to_string(); + } + +#ifndef JSON_NO_IO + /// @brief write string representation of the JSON pointer to stream + /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ + friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr) + { + o << ptr.to_string(); + return o; + } +#endif + + /// @brief append another JSON pointer at the end of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ + json_pointer& operator/=(const json_pointer& ptr) + { + reference_tokens.insert(reference_tokens.end(), + ptr.reference_tokens.begin(), + ptr.reference_tokens.end()); + return *this; + } + + /// @brief append an unescaped reference token at the end of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ + json_pointer& operator/=(string_t token) + { + push_back(std::move(token)); + return *this; + } + + /// @brief append an array index at the end of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ + json_pointer& operator/=(std::size_t array_idx) + { + return *this /= std::to_string(array_idx); + } + + /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ + friend json_pointer operator/(const json_pointer& lhs, + const json_pointer& rhs) + { + return json_pointer(lhs) /= rhs; + } + + /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ + friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param) + { + return json_pointer(lhs) /= std::move(token); + } + + /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ + friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx) + { + return json_pointer(lhs) /= array_idx; + } + + /// @brief returns the parent of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/ + json_pointer parent_pointer() const + { + if (empty()) + { + return *this; + } + + json_pointer res = *this; + res.pop_back(); + return res; + } + + /// @brief remove last reference token + /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/ + void pop_back() + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); + } + + reference_tokens.pop_back(); + } + + /// @brief return last reference token + /// @sa https://json.nlohmann.me/api/json_pointer/back/ + const string_t& back() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); + } + + return reference_tokens.back(); + } + + /// @brief append an unescaped token at the end of the reference pointer + /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ + void push_back(const string_t& token) + { + reference_tokens.push_back(token); + } + + /// @brief append an unescaped token at the end of the reference pointer + /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ + void push_back(string_t&& token) + { + reference_tokens.push_back(std::move(token)); + } + + /// @brief return whether pointer points to the root document + /// @sa https://json.nlohmann.me/api/json_pointer/empty/ + bool empty() const noexcept + { + return reference_tokens.empty(); + } + + private: + /*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index begins not with a digit + @throw out_of_range.404 if string @a s could not be converted to an integer + @throw out_of_range.410 if an array index exceeds size_type + */ + template + static typename BasicJsonType::size_type array_index(const string_t& s) + { + using size_type = typename BasicJsonType::size_type; + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) + { + JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr)); + } + + const char* p = s.c_str(); + char* p_end = nullptr; + errno = 0; // strtoull doesn't reset errno + const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int) + if (p == p_end // invalid input or empty string + || errno == ERANGE // out of range + || JSON_HEDLEY_UNLIKELY(static_cast(p_end - p) != s.size())) // incomplete read + { + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr)); + } + + // only triggered on special platforms (like 32bit), see also + // https://github.com/nlohmann/json/pull/2203 + if (res >= static_cast((std::numeric_limits::max)())) // NOLINT(runtime/int) + { + JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE + } + + return static_cast(res); + } + + JSON_PRIVATE_UNLESS_TESTED: + json_pointer top() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + private: + /*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ + template + BasicJsonType& get_and_create(BasicJsonType& j) const + { + auto* result = &j; + + // in case no reference tokens exist, return a reference to the JSON value + // j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->type()) + { + case detail::value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case detail::value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // create an entry in the array + result = &result->operator[](array_index(reference_token)); + break; + } + + /* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j)); + } + } + + return *result; + } + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + BasicJsonType& get_unchecked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->is_null()) + { + // check if reference token is a number + const bool nums = + std::all_of(reference_token.begin(), reference_token.end(), + [](const unsigned char x) + { + return std::isdigit(x); + }); + + // change value to array for numbers or "-" or to object otherwise + *ptr = (nums || reference_token == "-") + ? detail::value_t::array + : detail::value_t::object; + } + + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_data.m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + ptr = &ptr->operator[](array_index(reference_token)); + } + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + BasicJsonType& get_checked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, detail::concat( + "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), + ") is out of range"), ptr)); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" cannot be used for const access + JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); + } + + // use unchecked array access + ptr = &ptr->operator[](array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + const BasicJsonType& get_checked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, detail::concat( + "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), + ") is out of range"), ptr)); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + */ + template + bool contains(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + if (!ptr->contains(reference_token)) + { + // we did not find the key in the object + return false; + } + + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) + { + // invalid char + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) + { + if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) + { + // first char should be between '1' and '9' + return false; + } + for (std::size_t i = 1; i < reference_token.size(); i++) + { + if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) + { + // other char should be between '0' and '9' + return false; + } + } + } + + const auto idx = array_index(reference_token); + if (idx >= ptr->size()) + { + // index out of range + return false; + } + + ptr = &ptr->operator[](idx); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + { + // we do not expect primitive values if there is still a + // reference token to process + return false; + } + } + } + + // no reference token left means we found a primitive value + return true; + } + + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ + static std::vector split(const string_t& reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) + { + JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + std::size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == 0 (if slash == string_t::npos) + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == string_t::npos) + start = (slash == string_t::npos) ? 0 : slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (std::size_t pos = reference_token.find_first_of('~'); + pos != string_t::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + JSON_ASSERT(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || + (reference_token[pos + 1] != '0' && + reference_token[pos + 1] != '1'))) + { + JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr)); + } + } + + // finally, store the reference token + detail::unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + private: + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + template + static void flatten(const string_t& reference_string, + const BasicJsonType& value, + BasicJsonType& result) + { + switch (value.type()) + { + case detail::value_t::array: + { + if (value.m_data.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i) + { + flatten(detail::concat(reference_string, '/', std::to_string(i)), + value.m_data.m_value.array->operator[](i), result); + } + } + break; + } + + case detail::value_t::object: + { + if (value.m_data.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_data.m_value.object) + { + flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result); + } + } + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } + } + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ + template + static BasicJsonType + unflatten(const BasicJsonType& value) + { + if (JSON_HEDLEY_UNLIKELY(!value.is_object())) + { + JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value)); + } + + BasicJsonType result; + + // iterate the JSON object values + for (const auto& element : *value.m_data.m_value.object) + { + if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) + { + JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second)); + } + + // assign value to reference pointed to by JSON pointer; Note that if + // the JSON pointer is "" (i.e., points to the whole value), function + // get_and_create returns a reference to result itself. An assignment + // will then create a primitive value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; + } + + // can't use conversion operator because of ambiguity + json_pointer convert() const& + { + json_pointer result; + result.reference_tokens = reference_tokens; + return result; + } + + json_pointer convert()&& + { + json_pointer result; + result.reference_tokens = std::move(reference_tokens); + return result; + } + + public: +#if JSON_HAS_THREE_WAY_COMPARISON + /// @brief compares two JSON pointers for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + bool operator==(const json_pointer& rhs) const noexcept + { + return reference_tokens == rhs.reference_tokens; + } + + /// @brief compares JSON pointer and string for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer)) + bool operator==(const string_t& rhs) const + { + return *this == json_pointer(rhs); + } + + /// @brief 3-way compares two JSON pointers + template + std::strong_ordering operator<=>(const json_pointer& rhs) const noexcept // *NOPAD* + { + return reference_tokens <=> rhs.reference_tokens; // *NOPAD* + } +#else + /// @brief compares two JSON pointers for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator==(const json_pointer& lhs, + const json_pointer& rhs) noexcept; + + /// @brief compares JSON pointer and string for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator==(const json_pointer& lhs, + const StringType& rhs); + + /// @brief compares string and JSON pointer for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator==(const StringType& lhs, + const json_pointer& rhs); + + /// @brief compares two JSON pointers for inequality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator!=(const json_pointer& lhs, + const json_pointer& rhs) noexcept; + + /// @brief compares JSON pointer and string for inequality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator!=(const json_pointer& lhs, + const StringType& rhs); + + /// @brief compares string and JSON pointer for inequality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator!=(const StringType& lhs, + const json_pointer& rhs); + + /// @brief compares two JSON pointer for less-than + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator<(const json_pointer& lhs, + const json_pointer& rhs) noexcept; +#endif + + private: + /// the reference tokens + std::vector reference_tokens; +}; + +#if !JSON_HAS_THREE_WAY_COMPARISON +// functions cannot be defined inside class due to ODR violations +template +inline bool operator==(const json_pointer& lhs, + const json_pointer& rhs) noexcept +{ + return lhs.reference_tokens == rhs.reference_tokens; +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) +inline bool operator==(const json_pointer& lhs, + const StringType& rhs) +{ + return lhs == json_pointer(rhs); +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) +inline bool operator==(const StringType& lhs, + const json_pointer& rhs) +{ + return json_pointer(lhs) == rhs; +} + +template +inline bool operator!=(const json_pointer& lhs, + const json_pointer& rhs) noexcept +{ + return !(lhs == rhs); +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) +inline bool operator!=(const json_pointer& lhs, + const StringType& rhs) +{ + return !(lhs == rhs); +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) +inline bool operator!=(const StringType& lhs, + const json_pointer& rhs) +{ + return !(lhs == rhs); +} + +template +inline bool operator<(const json_pointer& lhs, + const json_pointer& rhs) noexcept +{ + return lhs.reference_tokens < rhs.reference_tokens; +} +#endif + +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/json_ref.hpp b/json/include/nlohmann/detail/json_ref.hpp new file mode 100644 index 0000000..b8bb6a7 --- /dev/null +++ b/json/include/nlohmann/detail/json_ref.hpp @@ -0,0 +1,78 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +class json_ref +{ + public: + using value_type = BasicJsonType; + + json_ref(value_type&& value) + : owned_value(std::move(value)) + {} + + json_ref(const value_type& value) + : value_ref(&value) + {} + + json_ref(std::initializer_list init) + : owned_value(init) + {} + + template < + class... Args, + enable_if_t::value, int> = 0 > + json_ref(Args && ... args) + : owned_value(std::forward(args)...) + {} + + // class should be movable only + json_ref(json_ref&&) noexcept = default; + json_ref(const json_ref&) = delete; + json_ref& operator=(const json_ref&) = delete; + json_ref& operator=(json_ref&&) = delete; + ~json_ref() = default; + + value_type moved_or_copied() const + { + if (value_ref == nullptr) + { + return std::move(owned_value); + } + return *value_ref; + } + + value_type const& operator*() const + { + return value_ref ? *value_ref : owned_value; + } + + value_type const* operator->() const + { + return &** this; + } + + private: + mutable value_type owned_value = nullptr; + value_type const* value_ref = nullptr; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/macro_scope.hpp b/json/include/nlohmann/detail/macro_scope.hpp new file mode 100644 index 0000000..97127a6 --- /dev/null +++ b/json/include/nlohmann/detail/macro_scope.hpp @@ -0,0 +1,482 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // declval, pair +#include +#include + +// This file contains all internal macro definitions (except those affecting ABI) +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +#include + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1914 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + +#ifndef JSON_HAS_RANGES + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + #define JSON_HAS_RANGES 0 + #elif defined(__cpp_lib_ranges) + #define JSON_HAS_RANGES 1 + #else + #define JSON_HAS_RANGES 0 + #endif +#endif + +#ifndef JSON_HAS_STATIC_RTTI + #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0 + #define JSON_HAS_STATIC_RTTI 1 + #else + #define JSON_HAS_STATIC_RTTI 0 + #endif +#endif + +#ifdef JSON_HAS_CPP_17 + #define JSON_INLINE_VARIABLE inline +#else + #define JSON_INLINE_VARIABLE +#endif + +#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else + #define JSON_NO_UNIQUE_ADDRESS +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +// allow disabling exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow overriding assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType, \ + class CustomBaseClass> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + +#ifndef JSON_USE_GLOBAL_UDLS + #define JSON_USE_GLOBAL_UDLS 1 +#endif diff --git a/json/include/nlohmann/detail/macro_unscope.hpp b/json/include/nlohmann/detail/macro_unscope.hpp new file mode 100644 index 0000000..c6620d1 --- /dev/null +++ b/json/include/nlohmann/detail/macro_unscope.hpp @@ -0,0 +1,45 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +// restore clang diagnostic settings +#if defined(__clang__) + #pragma clang diagnostic pop +#endif + +// clean up +#undef JSON_ASSERT +#undef JSON_INTERNAL_CATCH +#undef JSON_THROW +#undef JSON_PRIVATE_UNLESS_TESTED +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef JSON_EXPLICIT +#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL +#undef JSON_INLINE_VARIABLE +#undef JSON_NO_UNIQUE_ADDRESS +#undef JSON_DISABLE_ENUM_SERIALIZATION +#undef JSON_USE_GLOBAL_UDLS + +#ifndef JSON_TEST_KEEP_MACROS + #undef JSON_CATCH + #undef JSON_TRY + #undef JSON_HAS_CPP_11 + #undef JSON_HAS_CPP_14 + #undef JSON_HAS_CPP_17 + #undef JSON_HAS_CPP_20 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #undef JSON_HAS_THREE_WAY_COMPARISON + #undef JSON_HAS_RANGES + #undef JSON_HAS_STATIC_RTTI + #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#include diff --git a/json/include/nlohmann/detail/meta/call_std/begin.hpp b/json/include/nlohmann/detail/meta/call_std/begin.hpp new file mode 100644 index 0000000..364cc89 --- /dev/null +++ b/json/include/nlohmann/detail/meta/call_std/begin.hpp @@ -0,0 +1,17 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); + +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/meta/call_std/end.hpp b/json/include/nlohmann/detail/meta/call_std/end.hpp new file mode 100644 index 0000000..463f070 --- /dev/null +++ b/json/include/nlohmann/detail/meta/call_std/end.hpp @@ -0,0 +1,17 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); + +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/meta/cpp_future.hpp b/json/include/nlohmann/detail/meta/cpp_future.hpp new file mode 100644 index 0000000..412b5aa --- /dev/null +++ b/json/include/nlohmann/detail/meta/cpp_future.hpp @@ -0,0 +1,171 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2018 The Abseil Authors +// SPDX-License-Identifier: MIT + +#pragma once + +#include // array +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using uncvref_t = typename std::remove_cv::type>::type; + +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; + +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; + +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template +using index_sequence_for = make_index_sequence; + +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static JSON_INLINE_VARIABLE constexpr T value{}; +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr T static_const::value; +#endif + +template +inline constexpr std::array make_array(Args&& ... args) +{ + return std::array {{static_cast(std::forward(args))...}}; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/meta/detected.hpp b/json/include/nlohmann/detail/meta/detected.hpp new file mode 100644 index 0000000..1db9bf9 --- /dev/null +++ b/json/include/nlohmann/detail/meta/detected.hpp @@ -0,0 +1,70 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// https://en.cppreference.com/w/cpp/experimental/is_detected +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/meta/identity_tag.hpp b/json/include/nlohmann/detail/meta/identity_tag.hpp new file mode 100644 index 0000000..269deff --- /dev/null +++ b/json/include/nlohmann/detail/meta/identity_tag.hpp @@ -0,0 +1,21 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// dispatching helper struct +template struct identity_tag {}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/meta/is_sax.hpp b/json/include/nlohmann/detail/meta/is_sax.hpp new file mode 100644 index 0000000..4e02bc1 --- /dev/null +++ b/json/include/nlohmann/detail/meta/is_sax.hpp @@ -0,0 +1,159 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // size_t +#include // declval +#include // string + +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using null_function_t = decltype(std::declval().null()); + +template +using boolean_function_t = + decltype(std::declval().boolean(std::declval())); + +template +using number_integer_function_t = + decltype(std::declval().number_integer(std::declval())); + +template +using number_unsigned_function_t = + decltype(std::declval().number_unsigned(std::declval())); + +template +using number_float_function_t = decltype(std::declval().number_float( + std::declval(), std::declval())); + +template +using string_function_t = + decltype(std::declval().string(std::declval())); + +template +using binary_function_t = + decltype(std::declval().binary(std::declval())); + +template +using start_object_function_t = + decltype(std::declval().start_object(std::declval())); + +template +using key_function_t = + decltype(std::declval().key(std::declval())); + +template +using end_object_function_t = decltype(std::declval().end_object()); + +template +using start_array_function_t = + decltype(std::declval().start_array(std::declval())); + +template +using end_array_function_t = decltype(std::declval().end_array()); + +template +using parse_error_function_t = decltype(std::declval().parse_error( + std::declval(), std::declval(), + std::declval())); + +template +struct is_sax +{ + private: + static_assert(is_basic_json::value, + "BasicJsonType must be of type basic_json<...>"); + + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using exception_t = typename BasicJsonType::exception; + + public: + static constexpr bool value = + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value; +}; + +template +struct is_sax_static_asserts +{ + private: + static_assert(is_basic_json::value, + "BasicJsonType must be of type basic_json<...>"); + + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using exception_t = typename BasicJsonType::exception; + + public: + static_assert(is_detected_exact::value, + "Missing/invalid function: bool null()"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool boolean(bool)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool boolean(bool)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool number_integer(number_integer_t)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool number_unsigned(number_unsigned_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool number_float(number_float_t, const string_t&)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool string(string_t&)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool binary(binary_t&)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool start_object(std::size_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool key(string_t&)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool end_object()"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool start_array(std::size_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool end_array()"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool parse_error(std::size_t, const " + "std::string&, const exception&)"); +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/json/include/nlohmann/detail/meta/std_fs.hpp b/json/include/nlohmann/detail/meta/std_fs.hpp new file mode 100644 index 0000000..fd18039 --- /dev/null +++ b/json/include/nlohmann/detail/meta/std_fs.hpp @@ -0,0 +1,29 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#if JSON_HAS_EXPERIMENTAL_FILESYSTEM +#include +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +namespace std_fs = std::experimental::filesystem; +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END +#elif JSON_HAS_FILESYSTEM +#include +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +namespace std_fs = std::filesystem; +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END +#endif diff --git a/json/include/nlohmann/detail/meta/type_traits.hpp b/json/include/nlohmann/detail/meta/type_traits.hpp new file mode 100644 index 0000000..e1b000d --- /dev/null +++ b/json/include/nlohmann/detail/meta/type_traits.hpp @@ -0,0 +1,795 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval +#include // tuple +#include // char_traits + +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ + +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// used by exceptions create() member functions +// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// false_type otherwise +template +struct is_basic_json_context : + std::integral_constant < bool, + is_basic_json::type>::type>::value + || std::is_same::value > +{}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +template +using detect_key_compare = typename T::key_compare; + +template +struct has_key_compare : std::integral_constant::value> {}; + +// obtains the actual object key comparator +template +struct actual_object_comparator +{ + using object_t = typename BasicJsonType::object_t; + using object_comparator_t = typename BasicJsonType::default_object_comparator_t; + using type = typename std::conditional < has_key_compare::value, + typename object_t::key_compare, object_comparator_t>::type; +}; + +template +using actual_object_comparator_t = typename actual_object_comparator::type; + +///////////////// +// char_traits // +///////////////// + +// Primary template of char_traits calls std char_traits +template +struct char_traits : std::char_traits +{}; + +// Explicitly define char traits for unsigned char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = unsigned char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(EOF); + } +}; + +// Explicitly define char traits for signed char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = signed char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(EOF); + } +}; + +/////////////////// +// is_ functions // +/////////////////// + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B { }; +template +struct conjunction +: std::conditional(B::value), conjunction, B>::type {}; + +// https://en.cppreference.com/w/cpp/types/negation +template struct negation : std::integral_constant < bool, !B::value > { }; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +using range_value_t = value_type_t>>; + +// The following implementation of is_complete_type is taken from +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +// and is written by Xiang Fan who agreed to using it in this library. + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_constructible_string_type +{ + // launder type through decltype() to fix compilation failure on ICPC +#ifdef __INTEL_COMPILER + using laundered_type = decltype(std::declval()); +#else + using laundered_type = ConstructibleStringType; +#endif + + static constexpr auto value = + conjunction < + is_constructible, + is_detected_exact>::value; +}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < + is_detected::value&& + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> +{ + static constexpr bool value = + is_constructible>::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& + is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& + is_complete_type < + detected_t>::value >> +{ + using value_type = range_value_t; + + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; + +template +struct is_json_iterator_of : std::false_type {}; + +template +struct is_json_iterator_of : std::true_type {}; + +template +struct is_json_iterator_of : std::true_type +{}; + +// checks if a given type T is a template specialization of Primary +template