Skip to content

Commit

Permalink
switch from custom stringFormat to fmtlib
Browse files Browse the repository at this point in the history
The latter helps to avoid wrong format errors and is simpler to use.
Will be replaced by std::format once C++20 becomes mandatory.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
  • Loading branch information
neheb committed Nov 16, 2023
1 parent e8326ba commit d3a154a
Show file tree
Hide file tree
Showing 23 changed files with 133 additions and 152 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libexpat1-dev zlib1g-dev libbrotli-dev libinih-dev
sudo apt-get install -y libfmt-dev libexpat1-dev zlib1g-dev libbrotli-dev libinih-dev
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/on_PR_mac_matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
run: |
brew install ninja
brew install inih
brew install fmt
brew install googletest
- name: Build
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/on_PR_mac_special_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:
run: |
brew install ninja
brew install inih
brew install fmt
brew install googletest
- name: Build
Expand Down
33 changes: 31 additions & 2 deletions .github/workflows/on_PR_meson.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ jobs:
cc:p
cmake:p
curl:p
fmt:p
gtest:p
libinih:p
meson:p
Expand All @@ -126,6 +127,34 @@ jobs:
meson setup "${{github.workspace}}/build" -Dauto_features=${{matrix.deps}} -Dwarning_level=3 -Dcpp_std=c++20
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
Cygwin:
runs-on: windows-latest
strategy:
matrix:
deps: ['enabled', 'disabled']
platform: ['x86', 'x86_64']
name: Cygwin-${{matrix.platform}}-deps=${{matrix.deps}}
defaults:
run:
shell: C:\cygwin\bin\bash.exe --noprofile --norc -o igncr -eo pipefail '{0}'
steps:
- uses: actions/checkout@v4
- uses: cygwin/cygwin-install-action@v4
with:
platform: ${{matrix.platform}}
packages: :>
cmake
gcc-g++
meson
ninja
pkg-config
python3
libiconv-devel
- name: Compile and Test
run: |
meson setup build -Dauto_features=${{matrix.deps}} -Dwarning_level=3 -Dcpp_std=c++20
meson compile -C build --verbose
meson test -C build --verbose
MacOS:
runs-on: macos-latest
name: macOS-deps=${{matrix.deps}}
Expand All @@ -137,7 +166,7 @@ jobs:

- name: Install packages
run: |
brew install curl brotli inih expat googletest
brew install fmt curl brotli inih expat googletest
python3 -m pip install meson==0.54.1 ninja
- name: Compile and Test
Expand All @@ -154,7 +183,7 @@ jobs:
uses: vmactions/freebsd-vm@v1
with:
prepare: |
pkg install -y cmake curl ninja meson gettext pkgconf googletest expat inih brotli
pkg install -y cmake curl ninja meson gettext pkgconf googletest expat inih brotli libfmt
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dcpp_std=c++20
meson compile -C "${{github.workspace}}/build" --verbose
Expand Down
54 changes: 1 addition & 53 deletions .github/workflows/on_PR_windows_matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ jobs:
libiconv:p
libinih:p
zlib:p
fmt:p
- name: Build
run: |
Expand All @@ -131,56 +132,3 @@ jobs:
- name: Test
run: |
ctest --test-dir build --output-on-failure
cygwin:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
build_type: [Release]
shared_libraries: [ON]
platform: [x86_64]
name: Cygwin ${{matrix.platform}} - BuildType:${{matrix.build_type}} - SHARED:${{matrix.shared_libraries}}
env:
SHELLOPTS: igncr
defaults:
run:
shell: C:\cygwin\bin\bash.exe -eo pipefail '{0}'
steps:
# Make sure we don't check out scripts using Windows CRLF line endings
- run: git config --global core.autocrlf input
shell: pwsh
- uses: actions/checkout@v4

- name: Set up Cygwin
uses: cygwin/cygwin-install-action@v4
with:
platform: ${{matrix.platform}}
packages: >-
gcc-g++
cmake
ninja
pkg-config
python3
libbrotli-devel
libcurl-devel
libexpat-devel
libiconv-devel
libinih-devel
zlib-devel
- name: Build
run: |
cmake --preset base_windows \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} \
-DCONAN_AUTO_INSTALL=OFF \
-DEXIV2_BUILD_SAMPLES=OFF \
-DEXIV2_BUILD_UNIT_TESTS=OFF \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=OFF \
-S . -B build && \
cmake --build build --parallel
- name: Test
run: |
ctest --test-dir build --output-on-failure
1 change: 1 addition & 0 deletions .github/workflows/on_push_BasicWinLinMac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ jobs:
run: |
brew install ninja
brew install inih
brew install fmt
brew install googletest
- name: build and compile
Expand Down
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ endif()

include_directories(${CMAKE_BINARY_DIR}) # Make the exv_conf.h file visible for the full project

check_cxx_symbol_exists(__cpp_lib_format "format" HAVE_STD_FORMAT)
if(NOT HAVE_STD_FORMAT)
find_package(fmt REQUIRED)
endif()

if(EXIV2_ENABLE_XMP)
add_subdirectory(xmpsdk)
endif()
Expand Down
16 changes: 8 additions & 8 deletions ci/install_dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,46 +41,46 @@ distro_id=$(grep '^ID=' /etc/os-release|awk -F = '{print $2}'|sed 's/\"//g')

case "$distro_id" in
'fedora')
dnf -y --refresh install gcc-c++ clang cmake ninja-build expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel gmock-devel glibc-langpack-en inih-devel
dnf -y --refresh install gcc-c++ clang cmake ninja-build expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel gmock-devel glibc-langpack-en inih-devel fmt-devel
;;

'debian')
apt-get update
apt-get install -y cmake ninja-build g++ clang libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgmock-dev libxml2-utils libinih-dev
apt-get install -y cmake ninja-build g++ clang libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgmock-dev libxml2-utils libinih-dev libfmt-dev
# debian_build_gtest
;;

'arch')
pacman --noconfirm -Syu
pacman --noconfirm --needed -S gcc clang cmake ninja expat zlib brotli libssh curl gtest libinih
pacman --noconfirm --needed -S gcc clang cmake ninja expat zlib brotli libssh curl gtest libinih fmt
;;

'ubuntu')
apt-get update
apt-get install -y cmake ninja-build g++ clang libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgmock-dev libxml2-utils libinih-dev
apt-get install -y cmake ninja-build g++ clang libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgmock-dev libxml2-utils libinih-dev libfmt-dev
# debian_build_gtest
;;

'alpine')
apk update
apk add gcc g++ clang cmake samurai expat-dev zlib-dev brotli-dev libssh-dev curl-dev gtest gtest-dev gmock libintl gettext-dev libxml2-utils inih-dev inih-inireader-dev
apk add gcc g++ clang cmake samurai expat-dev zlib-dev brotli-dev libssh-dev curl-dev gtest gtest-dev gmock libintl gettext-dev libxml2-utils inih-dev inih-inireader-dev fmt-dev
;;

'rhel')
dnf clean all
dnf -y install gcc-c++ clang cmake ninja-build expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel inih-devel
dnf -y install gcc-c++ clang cmake ninja-build expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel inih-devel fmt-devel
;;

'centos')
dnf clean all
dnf -y install gcc-c++ clang cmake expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel git
dnf -y install gcc-c++ clang cmake expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel git fmt-devel
dnf -y --enablerepo=crb install ninja-build meson
centos_build_inih
;;

'opensuse-tumbleweed')
zypper --non-interactive refresh
zypper --non-interactive install gcc-c++ clang cmake ninja libexpat-devel zlib-devel libbrotli-devel libssh-devel libcurl-devel gmock libxml2-tools libinih-devel
zypper --non-interactive install gcc-c++ clang cmake ninja libexpat-devel zlib-devel libbrotli-devel libssh-devel libcurl-devel gmock libxml2-tools libinih-devel libfmt-devel
;;
*)
echo "Sorry, no predefined dependencies for your distribution $distro_id exist yet"
Expand Down
2 changes: 2 additions & 0 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ def requirements(self):

self.requires('inih/55')

self.requires('fmt/10.1.1')

if self.options.webready:
self.requires('libcurl/7.85.0')

Expand Down
4 changes: 4 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ deps = []
deps += cpp.find_library('ws2_32', required: host_machine.system() == 'windows')
deps += cpp.find_library('procstat', required: host_machine.system() == 'freebsd')

if not cpp.has_header_symbol('format', '__cpp_lib_format')
deps += dependency('fmt')
endif

if cpp.get_argument_syntax() == 'gcc' and cpp.version().version_compare('<9')
if host_machine.system() == 'linux' and cpp.get_define('_LIBCPP_VERSION', prefix: '#include <new>') == ''
deps += cpp.find_library('stdc++fs')
Expand Down
6 changes: 6 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,12 @@ else()
target_link_libraries(exiv2lib PRIVATE psapi ws2_32 shell32)
endif()

if(NOT HAVE_STD_FORMAT)
target_link_libraries(exiv2lib PRIVATE fmt::fmt)
target_link_libraries(exiv2lib_int PRIVATE fmt::fmt)
list(APPEND requires_private_list "fmt")
endif()

if(EXIV2_ENABLE_PNG)
target_link_libraries(exiv2lib PRIVATE ZLIB::ZLIB)
list(APPEND requires_private_list "zlib")
Expand Down
14 changes: 7 additions & 7 deletions src/bmffimage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ bool enableBMFF(bool enable) {
}

std::string Iloc::toString() const {
return Internal::stringFormat("ID = %u from,length = %u,%u", ID_, start_, length_);
return stringFormat("ID = {} from,length = {},{}", ID_, start_, length_);
}

BmffImage::BmffImage(BasicIo::UniquePtr io, bool /* create */) :
Expand Down Expand Up @@ -269,7 +269,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
if (bTrace) {
bLF = true;
out << Internal::indent(depth) << "Exiv2::BmffImage::boxHandler: " << toAscii(box_type)
<< Internal::stringFormat(" %8zd->%" PRIu64 " ", address, box_length);
<< stringFormat(" {:8}->{} ", address, box_length);
}

if (box_length == 1) {
Expand Down Expand Up @@ -366,7 +366,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
id = " *** XMP ***";
}
if (bTrace) {
out << Internal::stringFormat("ID = %3d ", ID) << name << " " << id;
out << stringFormat("ID = {:3} {} {}", ID, name, id);
}
} break;

Expand Down Expand Up @@ -444,7 +444,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
uint32_t ldata = data.read_uint32(skip + step - 4, endian_);
if (bTrace) {
out << Internal::indent(depth)
<< Internal::stringFormat("%8zd | %8zd | ID | %4u | %6u,%6u", address + skip, step, ID, offset, ldata)
<< stringFormat("{:8} | {:8} | ID | {:4} | {:6},{:6}", address + skip, step, ID, offset, ldata)
<< std::endl;
}
// save data for post-processing in meta box
Expand All @@ -463,7 +463,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
uint32_t height = data.read_uint32(skip, endian_);
skip += 4;
if (bTrace) {
out << "pixelWidth_, pixelHeight_ = " << Internal::stringFormat("%d, %d", width, height);
out << stringFormat("pixelWidth_, pixelHeight_ = {}, {}", width, height);
}
// HEIC files can have multiple ispe records
// Store largest width/height
Expand Down Expand Up @@ -678,8 +678,8 @@ void BmffImage::parseCr3Preview(const DataBuf& data, std::ostream& out, bool bTr
return "application/octet-stream";
}();
if (bTrace) {
out << Internal::stringFormat("width,height,size = %zu,%zu,%zu", nativePreview.width_, nativePreview.height_,
nativePreview.size_);
out << stringFormat("width,height,size = {},{},{}", nativePreview.width_, nativePreview.height_,
nativePreview.size_);
}
nativePreviews_.push_back(std::move(nativePreview));
}
Expand Down
2 changes: 1 addition & 1 deletion src/futils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ std::string getProcessPath() {
return "unknown"; // pathbuf not big enough
auto path = fs::path(pathbuf);
#elif defined(__sun__)
auto path = fs::read_symlink(Internal::stringFormat("/proc/%d/path/a.out", getpid()));
auto path = fs::read_symlink(stringFormat("/proc/%d/path/a.out", getpid()));
#elif defined(__unix__)
auto path = fs::read_symlink("/proc/self/exe");
#endif
Expand Down
9 changes: 4 additions & 5 deletions src/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,7 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct
throw Error(ErrorCode::kerTiffDirectoryTooLarge);

if (bFirst && bPrint) {
out << Internal::indent(depth) << Internal::stringFormat("STRUCTURE OF TIFF FILE (%c%c): ", c, c) << io.path()
<< std::endl;
out << Internal::indent(depth) << stringFormat("STRUCTURE OF TIFF FILE ({}{}): {}", c, c, io.path()) << std::endl;
}

// Read the dictionary
Expand Down Expand Up @@ -435,11 +434,11 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct

if (bPrint) {
const size_t address = start + 2 + i * 12;
const std::string offsetString = bOffsetIsPointer ? Internal::stringFormat("%10u", offset) : "";
const std::string offsetString = bOffsetIsPointer ? stringFormat("{:9}", offset) : "";

out << Internal::indent(depth)
<< Internal::stringFormat("%8zu | %#06x %-28s |%10s |%9u |%10s | ", address, tag, tagName(tag).c_str(),
typeName(type), count, offsetString.c_str());
<< stringFormat("{:8} | {:#06x} {:<28} | {:>9} | {:>8} | {:9} | ", address, tag, tagName(tag).c_str(),
typeName(type), count, offsetString);
if (isShortType(type)) {
for (size_t k = 0; k < kount; k++) {
out << sp << byteSwap2(buf, k * size, bSwap);
Expand Down
26 changes: 0 additions & 26 deletions src/image_int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,6 @@
#include <vector>

namespace Exiv2::Internal {
std::string stringFormat(const char* format, ...) {
std::string result;
std::vector<char> buffer;
size_t need = std::strlen(format) * 8; // initial guess
int rc = -1;

// vsnprintf writes at most size (2nd parameter) bytes (including \0)
// returns the number of bytes required for the formatted string excluding \0
// the following loop goes through:
// one iteration (if 'need' was large enough for the for formatted string)
// or two iterations (after the first call to vsnprintf we know the required length)
do {
buffer.resize(need + 1);
va_list args; // variable arg list
va_start(args, format); // args start after format
rc = vsnprintf(buffer.data(), buffer.size(), format, args);
va_end(args); // free the args
if (rc > 0)
need = static_cast<size_t>(rc);
} while (buffer.size() <= need);

if (rc > 0)
result = std::string(buffer.data(), need);
return result;
}

[[nodiscard]] std::string indent(size_t i) {
return std::string(2 * i, ' ');
}
Expand Down
Loading

0 comments on commit d3a154a

Please sign in to comment.