diff --git a/src/middle-pgsql.cpp b/src/middle-pgsql.cpp index 648e9e3fc..68ab77e64 100644 --- a/src/middle-pgsql.cpp +++ b/src/middle-pgsql.cpp @@ -169,7 +169,7 @@ void pgsql_parse_members(char const *string, osmium::memory::Buffer &buffer, while (*string != '}') { char type = string[0]; char *endp; - osmid_t id = strtoosmid(string + 1, &endp, 10); + osmid_t id = std::strtoll(string + 1, &endp, 10); // String points to the comma */ string = decode_upto(endp + 1, role); builder.add_member(osmium::char_to_item_type(type), id, role); @@ -187,7 +187,7 @@ void pgsql_parse_nodes(char const *string, osmium::memory::Buffer &buffer, osmium::builder::WayNodeListBuilder wnl_builder{buffer, &builder}; while (*string != '}') { char *ptr; - wnl_builder.add_node_ref(strtoosmid(string, &ptr, 10)); + wnl_builder.add_node_ref(std::strtoll(string, &ptr, 10)); string = ptr; if (*string == ',') { ++string; diff --git a/src/osmtypes.hpp b/src/osmtypes.hpp index a461aa406..c0b27a515 100644 --- a/src/osmtypes.hpp +++ b/src/osmtypes.hpp @@ -1,17 +1,20 @@ #ifndef OSM2PGSQL_OSMTYPES_HPP #define OSM2PGSQL_OSMTYPES_HPP -/* Data types to hold OSM node, segment, way data */ - -// when __cplusplus is defined, we need to define this macro as well -// to get the print format specifiers in the inttypes.h header. -#define __STDC_FORMAT_MACROS -#include +/** + * \file + * + * This file is part of osm2pgsql (https://github.com/openstreetmap/osm2pgsql). + * + * In this file some basic (OSM) data types are defined. + */ #include -#include +#include +#include #include #include +#include #include #include @@ -19,7 +22,6 @@ #include using osmid_t = std::int64_t; -#define strtoosmid strtoll struct member { @@ -64,7 +66,7 @@ struct tag_t std::string key; std::string value; - operator std::pair const() const + operator std::pair const() const noexcept { return std::pair(key.c_str(), value.c_str()); diff --git a/src/output-flex.cpp b/src/output-flex.cpp index ccc7dfd46..3cc58b3f1 100644 --- a/src/output-flex.cpp +++ b/src/output-flex.cpp @@ -11,7 +11,6 @@ #include "output-flex.hpp" #include "pgsql.hpp" #include "reprojection.hpp" -#include "taginfo-impl.hpp" #include "util.hpp" #include "version.hpp" #include "wkb.hpp" diff --git a/src/output-multi.hpp b/src/output-multi.hpp index b6de7b80f..d511bbbb6 100644 --- a/src/output-multi.hpp +++ b/src/output-multi.hpp @@ -20,7 +20,7 @@ class options_t; class table_t; class tagtransform_t; -struct export_list; +class export_list; struct middle_query_t; class output_multi_t : public output_t diff --git a/src/output-pgsql.hpp b/src/output-pgsql.hpp index ed3ef707d..c0f2e73a7 100644 --- a/src/output-pgsql.hpp +++ b/src/output-pgsql.hpp @@ -73,7 +73,7 @@ class output_pgsql_t : public output_t std::unique_ptr m_tagtransform; //enable output of a generated way_area tag to either hstore or its own column - int m_enable_way_area; + bool m_enable_way_area; std::array, t_MAX> m_tables; diff --git a/src/table.cpp b/src/table.cpp index 22b40f988..ea95a95b1 100644 --- a/src/table.cpp +++ b/src/table.cpp @@ -389,7 +389,7 @@ void table_t::write_hstore_columns(taglist_t const &tags) void table_t::escape_type(std::string const &value, ColumnType flags) { switch (flags) { - case COLUMN_TYPE_INT: { + case ColumnType::INT: { // For integers we take the first number, or the average if it's a-b long long from, to; // limit number of digits parsed to avoid undefined behaviour in sscanf @@ -413,7 +413,7 @@ void table_t::escape_type(std::string const &value, ColumnType flags) } break; } - case COLUMN_TYPE_REAL: + case ColumnType::REAL: /* try to "repair" real values as follows: * assume "," to be a decimal mark which need to be replaced by "." * like int4 take the first number, or the average if it's a-b @@ -446,7 +446,7 @@ void table_t::escape_type(std::string const &value, ColumnType flags) } break; } - case COLUMN_TYPE_TEXT: + case ColumnType::TEXT: m_copy.add_column(value); break; } diff --git a/src/taginfo-impl.hpp b/src/taginfo-impl.hpp index 68e267ac3..d9f8624e2 100644 --- a/src/taginfo-impl.hpp +++ b/src/taginfo-impl.hpp @@ -3,11 +3,14 @@ #include "osmtypes.hpp" #include "taginfo.hpp" + +#include + #include #include #include -enum column_flags +enum column_flags : unsigned int { FLAG_POLYGON = 1, /* For polygon table */ FLAG_LINEAR = 2, /* For lines table */ @@ -21,36 +24,37 @@ enum column_flags FLAG_REAL_TYPE = 64 /* column value should be converted to double */ }; +/* Table columns, representing key= tags */ struct taginfo { - taginfo(); - taginfo(taginfo const &); - ColumnType column_type() const { if (flags & FLAG_INT_TYPE) { - return COLUMN_TYPE_INT; + return ColumnType::INT; } if (flags & FLAG_REAL_TYPE) { - return COLUMN_TYPE_REAL; + return ColumnType::REAL; } - return COLUMN_TYPE_TEXT; + return ColumnType::TEXT; } - std::string name, type; - unsigned flags; + std::string name; + std::string type; + unsigned int flags = 0; }; -struct export_list +/* list of exported tags */ +class export_list { - void add(osmium::item_type id, taginfo const &info); - std::vector &get(osmium::item_type id); - std::vector const &get(osmium::item_type id) const; +public: + void add(osmium::item_type type, taginfo const &info); + std::vector const &get(osmium::item_type type) const noexcept; - columns_t normal_columns(osmium::item_type id) const; - bool has_column(osmium::item_type id, char const *name) const; + columns_t normal_columns(osmium::item_type type) const; + bool has_column(osmium::item_type type, char const *name) const; - std::vector> exportList; /* Indexed osmium nwr index */ +private: + osmium::nwr_array> m_export_list; }; /* Parse a comma or whitespace delimited list of tags to apply to @@ -61,9 +65,9 @@ unsigned parse_tag_flags(std::string const &flags, int lineno); /* Parse an osm2pgsql "pgsql" backend format style file, putting * the results in the `exlist` argument. * - * Returns 1 if the 'way_area' column should (implicitly) exist, or - * 0 if it should be suppressed. + * Returns `true` if the 'way_area' column should (implicitly) exist, or + * `false` if it should be suppressed. */ -int read_style_file(std::string const &filename, export_list *exlist); +bool read_style_file(std::string const &filename, export_list *exlist); #endif // OSM2PGSQL_TAGINFO_IMPL_HPP diff --git a/src/taginfo.cpp b/src/taginfo.cpp index 845b6d523..ed8eb9b76 100644 --- a/src/taginfo.cpp +++ b/src/taginfo.cpp @@ -1,8 +1,6 @@ #include "format.hpp" #include "taginfo-impl.hpp" -#include "util.hpp" -#include #include #include #include @@ -10,61 +8,20 @@ #include -static std::map const tagflags = { - {"polygon", FLAG_POLYGON}, {"linear", FLAG_LINEAR}, - {"nocache", FLAG_NOCACHE}, {"delete", FLAG_DELETE}, - {"phstore", FLAG_PHSTORE}, {"nocolumn", FLAG_NOCOLUMN}}; - -static std::map const tagtypes = { - {"smallint", FLAG_INT_TYPE}, {"integer", FLAG_INT_TYPE}, - {"bigint", FLAG_INT_TYPE}, {"int2", FLAG_INT_TYPE}, - {"int4", FLAG_INT_TYPE}, {"int8", FLAG_INT_TYPE}, - {"real", FLAG_REAL_TYPE}, {"double precision", FLAG_REAL_TYPE}}; - -taginfo::taginfo() : name(), type(), flags(0) {} - -taginfo::taginfo(taginfo const &other) -: name(other.name), type(other.type), flags(other.flags) -{} - -void export_list::add(osmium::item_type id, taginfo const &info) +void export_list::add(osmium::item_type type, taginfo const &info) { - std::vector &infos = get(id); - infos.push_back(info); + m_export_list(type).push_back(info); } -std::vector &export_list::get(osmium::item_type id) +std::vector const &export_list::get(osmium::item_type type) const + noexcept { - auto const idx = item_type_to_nwr_index(id); - if (idx >= exportList.size()) { - exportList.resize(idx + 1); - } - return exportList[idx]; + return m_export_list(type); } -std::vector const &export_list::get(osmium::item_type id) const +bool export_list::has_column(osmium::item_type type, char const *name) const { - // this fakes as if we have infinite taginfo vectors, but - // means we don't actually have anything allocated unless - // the info object has been assigned. - static const std::vector empty; - - auto const idx = item_type_to_nwr_index(id); - if (idx < exportList.size()) { - return exportList[idx]; - } - - return empty; -} - -bool export_list::has_column(osmium::item_type id, char const *name) const -{ - auto const idx = item_type_to_nwr_index(id); - if (idx >= exportList.size()) { - return false; - } - - for (auto const &info : exportList[idx]) { + for (auto const &info : m_export_list(type)) { if (info.name == name) { return true; } @@ -73,11 +30,11 @@ bool export_list::has_column(osmium::item_type id, char const *name) const return false; } -columns_t export_list::normal_columns(osmium::item_type id) const +columns_t export_list::normal_columns(osmium::item_type type) const { columns_t columns; - for (auto const &info : get(id)) { + for (auto const &info : m_export_list(type)) { if (!(info.flags & (FLAG_DELETE | FLAG_NOCOLUMN))) { columns.emplace_back(info.name, info.type, info.column_type()); } @@ -88,6 +45,11 @@ columns_t export_list::normal_columns(osmium::item_type id) const unsigned parse_tag_flags(std::string const &flags, int lineno) { + static std::map const tagflags = { + {"polygon", FLAG_POLYGON}, {"linear", FLAG_LINEAR}, + {"nocache", FLAG_NOCACHE}, {"delete", FLAG_DELETE}, + {"phstore", FLAG_PHSTORE}, {"nocolumn", FLAG_NOCOLUMN}}; + unsigned temp_flags = 0; for (auto const &flag_name : osmium::split_string(flags, ",\r\n")) { @@ -103,53 +65,70 @@ unsigned parse_tag_flags(std::string const &flags, int lineno) return temp_flags; } -int read_style_file(std::string const &filename, export_list *exlist) +/** + * Get the tag type. For unknown types, 0 will be returned. + */ +static unsigned get_tag_type(std::string const &tag) +{ + static std::map const tagtypes = { + {"smallint", FLAG_INT_TYPE}, {"integer", FLAG_INT_TYPE}, + {"bigint", FLAG_INT_TYPE}, {"int2", FLAG_INT_TYPE}, + {"int4", FLAG_INT_TYPE}, {"int8", FLAG_INT_TYPE}, + {"real", FLAG_REAL_TYPE}, {"double precision", FLAG_REAL_TYPE}}; + + auto const typ = tagtypes.find(tag); + if (typ != tagtypes.end()) { + return typ->second; + } + + return 0; +} + +bool read_style_file(std::string const &filename, export_list *exlist) { - FILE *in; - int lineno = 0; - int num_read = 0; char osmtype[24]; char tag[64]; char datatype[24]; char flags[128]; - char *str; - int fields; - struct taginfo temp; - char buffer[1024]; - int enable_way_area = 1; + bool enable_way_area = true; - in = fopen(filename.c_str(), "rt"); + FILE *const in = std::fopen(filename.c_str(), "rt"); if (!in) { throw std::runtime_error{"Couldn't open style file '{}': {}"_format( filename, std::strerror(errno))}; } + char buffer[1024]; + int lineno = 0; + bool read_valid_column = false; //for each line of the style file - while (fgets(buffer, sizeof(buffer), in) != nullptr) { + while (std::fgets(buffer, sizeof(buffer), in) != nullptr) { ++lineno; //find where a comment starts and terminate the string there - str = std::strchr(buffer, '#'); + char *const str = std::strchr(buffer, '#'); if (str) { *str = '\0'; } //grab the expected fields for this row - fields = sscanf(buffer, "%23s %63s %23s %127s", osmtype, tag, datatype, - flags); + int const fields = std::sscanf(buffer, "%23s %63s %23s %127s", osmtype, + tag, datatype, flags); if (fields <= 0) { /* Blank line */ continue; } + if (fields < 3) { - fmt::print(stderr, "Error reading style file line {} (fields={})\n", - lineno, fields); - fclose(in); - util::exit_nicely(); + std::fclose(in); + throw std::runtime_error{ + "Error reading style file line {} (fields={})"_format(lineno, + fields)}; } //place to keep info about this tag - temp.name.assign(tag); - temp.type.assign(datatype); + taginfo temp; + temp.name = tag; + temp.type = datatype; temp.flags = parse_tag_flags(flags, lineno); // check for special data types, by default everything is handled as text @@ -158,23 +137,19 @@ int read_style_file(std::string const &filename, export_list *exlist) // want to convert it back and forth between string and real later. The code // will provide a string suitable for the database already. if (temp.name != "way_area") { - auto const typ = tagtypes.find(temp.type); - if (typ != tagtypes.end()) { - temp.flags |= typ->second; - } + temp.flags |= get_tag_type(temp.type); } if ((temp.flags != FLAG_DELETE) && ((temp.name.find('?') != std::string::npos) || (temp.name.find('*') != std::string::npos))) { - fmt::print(stderr, "wildcard '{}' in non-delete style entry\n", - temp.name); - fclose(in); - util::exit_nicely(); + std::fclose(in); + throw std::runtime_error{ + "wildcard '{}' in non-delete style entry"_format(temp.name)}; } if ((temp.name == "way_area") && (temp.flags == FLAG_DELETE)) { - enable_way_area = 0; + enable_way_area = false; } bool kept = false; @@ -193,22 +168,26 @@ int read_style_file(std::string const &filename, export_list *exlist) //do we really want to completely quit on an unusable line? if (!kept) { - fclose(in); + std::fclose(in); throw std::runtime_error{ "Weird style line {}:{}"_format(filename, lineno)}; } - ++num_read; + + read_valid_column = true; } - if (ferror(in)) { - int err = errno; - fclose(in); + if (std::ferror(in)) { + int const err = errno; + std::fclose(in); throw std::runtime_error{"{}: {}"_format(filename, std::strerror(err))}; } - fclose(in); - if (num_read == 0) { + + std::fclose(in); + + if (!read_valid_column) { throw std::runtime_error{"Unable to parse any valid columns from " "the style file. Aborting."}; } + return enable_way_area; } diff --git a/src/taginfo.hpp b/src/taginfo.hpp index da126730f..8a77d4e47 100644 --- a/src/taginfo.hpp +++ b/src/taginfo.hpp @@ -4,11 +4,11 @@ #include #include -enum ColumnType +enum class ColumnType { - COLUMN_TYPE_INT, - COLUMN_TYPE_REAL, - COLUMN_TYPE_TEXT + INT, + REAL, + TEXT }; struct Column @@ -24,10 +24,4 @@ struct Column using columns_t = std::vector; -/* Table columns, representing key= tags */ -struct taginfo; - -/* list of exported tags */ -struct export_list; - #endif // OSM2PGSQL_TAGINFO_HPP diff --git a/src/tagtransform.hpp b/src/tagtransform.hpp index 142515e01..07096e010 100644 --- a/src/tagtransform.hpp +++ b/src/tagtransform.hpp @@ -7,8 +7,8 @@ #include "osmtypes.hpp" +class export_list; class options_t; -struct export_list; class tagtransform_t {