diff --git a/.github/workflows/macos_14.yml b/.github/workflows/macos_14.yml new file mode 100644 index 00000000..fba436ae --- /dev/null +++ b/.github/workflows/macos_14.yml @@ -0,0 +1,26 @@ +name: Build on macOS 14 + +on: [push, pull_request] + +jobs: + build: + runs-on: macos-14 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + brew install boost cryptopp fmt fcgi yajl libmemcached libpqxx postgresql + + - name: build + run: | + mkdir build && cd build && \ + CXXFLAGS="-Wall -Wextra -Wpedantic -Wno-unused-parameter" cmake .. -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Release && \ + make -j${nproc} && \ + ctest --output-on-failure -E "db" + + - name: Running openstreetmap-cgimap + run: | + ./build/openstreetmap-cgimap --help diff --git a/contrib/sjparser/library/CMakeLists.txt b/contrib/sjparser/library/CMakeLists.txt index e834af06..cb8468b6 100644 --- a/contrib/sjparser/library/CMakeLists.txt +++ b/contrib/sjparser/library/CMakeLists.txt @@ -1,7 +1,4 @@ -find_library(YAJL_LIB yajl) -if(NOT YAJL_LIB) - message(FATAL_ERROR "Can't find yajl library") -endif() +find_package(YAJL 2 REQUIRED) add_library(sjparser STATIC sjparser/parsing_error.cpp @@ -42,7 +39,7 @@ set_target_properties(sjparser PROPERTIES OUTPUT_NAME sjparser_static) setup_compilation_options(sjparser) -target_link_libraries(sjparser PUBLIC ${YAJL_LIB}) +target_link_libraries(sjparser PUBLIC YAJL::YAJL) target_include_directories(sjparser PUBLIC $ @@ -60,7 +57,7 @@ if(SJPARSER_BUILD_SHARED_LIBRARY) setup_compilation_options(sjparser_shared) - target_link_libraries(sjparser_shared PUBLIC ${YAJL_LIB}) + target_link_libraries(sjparser_shared PUBLIC YAJL::YAJL) target_include_directories(sjparser_shared PUBLIC $ diff --git a/include/cgimap/api06/changeset_upload/node.hpp b/include/cgimap/api06/changeset_upload/node.hpp index 870e39d7..cb63bdad 100644 --- a/include/cgimap/api06/changeset_upload/node.hpp +++ b/include/cgimap/api06/changeset_upload/node.hpp @@ -32,6 +32,7 @@ class Node : public OSMObject { double _lat; +#if !defined(__APPLE__) auto [_, ec] = std::from_chars(lat.data(), lat.data() + lat.size(), _lat); if (ec == std::errc()) @@ -42,12 +43,26 @@ class Node : public OSMObject { throw payload_error("Latitude value is too large"); else throw payload_error("Unexpected parsing error"); + +#else + + try { + _lat = std::stod(lat); + } catch (std::invalid_argument &e) { + throw payload_error("Latitude is not numeric"); + } catch (std::out_of_range &e) { + throw payload_error("Latitude value is too large"); + } + set_lat(_lat); + +#endif } void set_lon(const std::string &lon) { double _lon; +#if !defined(__APPLE__) auto [_, ec] = std::from_chars(lon.data(), lon.data() + lon.size(), _lon); if (ec == std::errc()) @@ -58,6 +73,20 @@ class Node : public OSMObject { throw payload_error("Longitude value is too large"); else throw payload_error("Unexpected parsing error"); + +#else + + try { + _lon = std::stod(lon); + } catch (std::invalid_argument &e) { + throw payload_error("Longitude is not numeric"); + } catch (std::out_of_range &e) { + throw payload_error("Longitude value is too large"); + } + + set_lon(_lon); + +#endif } void set_lat(double lat) { diff --git a/include/cgimap/backend/apidb/pqxx_string_traits.hpp b/include/cgimap/backend/apidb/pqxx_string_traits.hpp index 7e64f672..01f31c90 100644 --- a/include/cgimap/backend/apidb/pqxx_string_traits.hpp +++ b/include/cgimap/backend/apidb/pqxx_string_traits.hpp @@ -116,7 +116,7 @@ struct array_string_traits template<> \ struct string_traits : cgimap::array_string_traits {}; \ \ - template<> std::string const type_name{#type}; \ + template<> inline std::string const type_name{#type}; \ #endif @@ -127,7 +127,6 @@ PQXX_ARRAY_STRING_TRAITS(std::vector); PQXX_ARRAY_STRING_TRAITS(std::vector); PQXX_ARRAY_STRING_TRAITS(std::set); PQXX_ARRAY_STRING_TRAITS(std::vector); -PQXX_ARRAY_STRING_TRAITS(std::vector); } // namespace pqxx diff --git a/include/cgimap/util.hpp b/include/cgimap/util.hpp index f32ec00f..5183e79d 100644 --- a/include/cgimap/util.hpp +++ b/include/cgimap/util.hpp @@ -27,8 +27,33 @@ #include #include +#include +#if __APPLE__ +// NOTE: is deprecated in C++17 and removed in C++26 (see P2871R3). + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" + +#include +#include +#include + +inline std::size_t unicode_strlen(const std::string& utf8) +{ + + try { + return std::wstring_convert< std::codecvt_utf8, char32_t >{}.from_bytes(utf8).size(); + } catch(std::range_error) { + throw http::bad_request("Invalid UTF-8 string encountered"); + } +} + +#pragma clang diagnostic pop + +#else + inline size_t unicode_strlen(const std::string & s) { const char* mbstr = s.c_str(); @@ -43,6 +68,8 @@ inline size_t unicode_strlen(const std::string & s) return len; } +#endif + inline std::string escape(std::string_view input) { int n = 0; diff --git a/src/backend/apidb/changeset_upload/relation_updater.cpp b/src/backend/apidb/changeset_upload/relation_updater.cpp index 87ed7959..c35ec4c4 100644 --- a/src/backend/apidb/changeset_upload/relation_updater.cpp +++ b/src/backend/apidb/changeset_upload/relation_updater.cpp @@ -1239,17 +1239,16 @@ void ApiDB_Relation_Updater::update_current_relations( m.prepare("update_current_relations", R"( - WITH u(id, changeset_id, visible, version) AS ( + WITH u(id, changeset_id, version) AS ( SELECT * FROM UNNEST( CAST($1 AS bigint[]), CAST($2 AS bigint[]), - CAST($3 AS boolean[]), - CAST($4 AS bigint[]) + CAST($3 AS bigint[]) ) ) UPDATE current_relations AS r SET changeset_id = u.changeset_id, - visible = u.visible, + visible = CAST($4 as boolean), timestamp = (now() at time zone 'utc'), version = u.version + 1 FROM u @@ -1260,20 +1259,18 @@ void ApiDB_Relation_Updater::update_current_relations( std::vector ids; std::vector cs; - std::vector visibles; std::vector versions; std::map id_to_old_id; for (const auto &relation : relations) { ids.emplace_back(relation.id); cs.emplace_back(relation.changeset_id); - visibles.push_back(visible); versions.emplace_back(relation.version); id_to_old_id[relation.id] = relation.old_id; } pqxx::result r = - m.exec_prepared("update_current_relations", ids, cs, visibles, versions); + m.exec_prepared("update_current_relations", ids, cs, versions, visible); if (r.affected_rows() != relations.size()) throw http::server_error("Could not update all current relations"); diff --git a/src/backend/apidb/changeset_upload/way_updater.cpp b/src/backend/apidb/changeset_upload/way_updater.cpp index c20233d0..22e39a18 100644 --- a/src/backend/apidb/changeset_upload/way_updater.cpp +++ b/src/backend/apidb/changeset_upload/way_updater.cpp @@ -642,17 +642,16 @@ void ApiDB_Way_Updater::update_current_ways(const std::vector &ways, return; m.prepare("update_current_ways", R"( - WITH u(id, changeset_id, visible, version) AS ( + WITH u(id, changeset_id, version) AS ( SELECT * FROM UNNEST( CAST($1 AS bigint[]), CAST($2 AS bigint[]), - CAST($3 AS boolean[]), - CAST($4 AS bigint[]) + CAST($3 AS bigint[]) ) ) UPDATE current_ways AS w SET changeset_id = u.changeset_id, - visible = u.visible, + visible = CAST($4 as boolean), timestamp = (now() at time zone 'utc'), version = u.version + 1 FROM u @@ -663,20 +662,18 @@ void ApiDB_Way_Updater::update_current_ways(const std::vector &ways, std::vector ids; std::vector cs; - std::vector visibles; std::vector versions; std::map id_to_old_id; for (const auto &way : ways) { ids.emplace_back(way.id); cs.emplace_back(way.changeset_id); - visibles.push_back(visible); versions.emplace_back(way.version); id_to_old_id[way.id] = way.old_id; } pqxx::result r = - m.exec_prepared("update_current_ways", ids, cs, visibles, versions); + m.exec_prepared("update_current_ways", ids, cs, versions, visible); if (r.affected_rows() != ways.size()) throw http::server_error("Could not update all current ways"); diff --git a/src/backend/apidb/pgsql_update.cpp b/src/backend/apidb/pgsql_update.cpp index f4ca9f61..703b0063 100644 --- a/src/backend/apidb/pgsql_update.cpp +++ b/src/backend/apidb/pgsql_update.cpp @@ -176,7 +176,7 @@ uint64_t pgsql_update::get_bbox_size_limit(osm_user_id_t uid) auto row = res[0]; auto bbox_size_limit = row[0].as(); - return std::max(bbox_size_limit, 0L); + return (bbox_size_limit < 0 ? 0 : bbox_size_limit); } } diff --git a/src/fcgi_request.cpp b/src/fcgi_request.cpp index 0b6cd2f1..52a074ed 100644 --- a/src/fcgi_request.cpp +++ b/src/fcgi_request.cpp @@ -158,7 +158,7 @@ int fcgi_request::accept_r() { } else { char err_buf[1024]; out << "error accepting request: "; - if (strerror_r(errno, err_buf, sizeof err_buf) == nullptr) { + if (strerror_r(errno, err_buf, sizeof err_buf) == 0) { // NOLINT(modernize-use-nullptr) out << err_buf; } else { out << "error encountered while getting error message"; diff --git a/src/main.cpp b/src/main.cpp index 29e91548..f875400d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,6 +77,12 @@ void reload(int) { reload_requested = true; } +#if __APPLE__ + #ifndef HOST_NAME_MAX + #define HOST_NAME_MAX 255 + #endif +#endif + /** * make a string to be used as the generator header * attribute of output files. includes some instance diff --git a/src/request.cpp b/src/request.cpp index 0d1ce321..9342924d 100644 --- a/src/request.cpp +++ b/src/request.cpp @@ -92,8 +92,8 @@ void request::check_workflow(workflow_status this_stage) { } else if (m_workflow_status > this_stage) { // oops - workflow is more advanced than the function which called // this, so a workflow violation has occurred. - throw std::runtime_error(fmt::format("Can't move backwards in the request workflow from {} to {}.", - m_workflow_status, this_stage)); + throw std::runtime_error(fmt::format("Can't move backwards in the request workflow from {:d} to {:d}.", + static_cast(m_workflow_status), static_cast(this_stage))); } }