aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/proj/io.hpp2
-rwxr-xr-xscripts/cppcheck.sh2
-rw-r--r--src/Makefile.am17
-rw-r--r--src/c_api.cpp123
-rw-r--r--src/io.cpp35
-rw-r--r--src/lib_proj.cmake2
-rw-r--r--src/pj_wkt1_generated_parser.c1664
-rw-r--r--src/pj_wkt1_generated_parser.h89
-rw-r--r--src/pj_wkt1_grammar.y301
-rw-r--r--src/pj_wkt1_parser.cpp221
-rw-r--r--src/pj_wkt1_parser.h54
-rw-r--r--src/proj.h14
-rw-r--r--src/projinfo.cpp34
-rwxr-xr-xtest/cli/testprojinfo4
-rw-r--r--test/cli/testprojinfo_out.dist25
-rw-r--r--test/unit/test_c_api.cpp201
-rw-r--r--test/unit/test_io.cpp42
-rw-r--r--test/unit/test_operation.cpp28
-rwxr-xr-xtravis/csa/install.sh2
19 files changed, 2734 insertions, 126 deletions
diff --git a/include/proj/io.hpp b/include/proj/io.hpp
index c0d4fef5..3d09e7d3 100644
--- a/include/proj/io.hpp
+++ b/include/proj/io.hpp
@@ -620,7 +620,7 @@ class PROJ_GCC_DLL WKTParser {
attachDatabaseContext(const DatabaseContextPtr &dbContext);
PROJ_DLL WKTParser &setStrict(bool strict);
- PROJ_DLL std::vector<std::string> warningList() const;
+ PROJ_DLL std::list<std::string> warningList() const;
PROJ_DLL util::BaseObjectNNPtr
createFromWKT(const std::string &wkt); // throw(ParsingException)
diff --git a/scripts/cppcheck.sh b/scripts/cppcheck.sh
index bd677e3d..76a540aa 100755
--- a/scripts/cppcheck.sh
+++ b/scripts/cppcheck.sh
@@ -34,7 +34,7 @@ done
ret_code=0
-grep -v "unmatchedSuppression" ${LOG_FILE} | grep -v "nn.hpp" > ${LOG_FILE}.tmp
+grep -v "unmatchedSuppression" ${LOG_FILE} | grep -v "nn.hpp" | grep -v "pj_wkt1_generated_parser" > ${LOG_FILE}.tmp
mv ${LOG_FILE}.tmp ${LOG_FILE}
if grep "null pointer" ${LOG_FILE} ; then
diff --git a/src/Makefile.am b/src/Makefile.am
index 99158f02..9cf1eb88 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,8 +14,9 @@ include_HEADERS = proj.h proj_experimental.h proj_constants.h proj_api.h geodesi
org_proj4_PJ.h proj_symbol_rename.h
EXTRA_DIST = bin_cct.cmake bin_gie.cmake bin_cs2cs.cmake \
- bin_geod.cmake bin_nad2bin.cmake bin_proj.cmake bin_projinfo.cmake \
- lib_proj.cmake CMakeLists.txt bin_geodtest.cmake geodtest.c
+ bin_geod.cmake bin_nad2bin.cmake bin_proj.cmake bin_projinfo.cmake \
+ lib_proj.cmake CMakeLists.txt bin_geodtest.cmake geodtest.c \
+ pj_wkt1_grammar.y
proj_SOURCES = proj.c gen_cheb.c p_series.c
projinfo_SOURCES = projinfo.cpp
@@ -94,7 +95,17 @@ libproj_la_SOURCES = \
\
proj_4D_api.c PJ_cart.c PJ_pipeline.c PJ_horner.c PJ_helmert.c \
PJ_vgridshift.c PJ_hgridshift.c PJ_unitconvert.c PJ_molodensky.c \
- PJ_deformation.c pj_internal.c PJ_axisswap.c PJ_affine.c
+ PJ_deformation.c pj_internal.c PJ_axisswap.c PJ_affine.c \
+ pj_wkt1_parser.h pj_wkt1_parser.cpp \
+ pj_wkt1_generated_parser.h pj_wkt1_generated_parser.c
+
+
+# The sed hack is to please MSVC
+wkt1_parser:
+ bison --no-lines -d -p pj_wkt1_ -o$(top_srcdir)/src/pj_wkt1_generated_parser.c $(top_srcdir)/src/pj_wkt1_grammar.y
+ sed "s/\*yyssp = yystate/\*yyssp = (yytype_int16)yystate/" < $(top_srcdir)/src/pj_wkt1_generated_parser.c | sed "s/yyerrorlab:/#if 0\nyyerrorlab:/" | sed "s/yyerrlab1:/#endif\nyyerrlab1:/" | sed "s/for (yylen = 0; yystr\[yylen\]; yylen++)/for (yylen = 0; yystr \&\& yystr\[yylen\]; yylen++)/" > $(top_srcdir)/src/pj_wkt1_generated_parser.c.tmp
+ mv $(top_srcdir)/src/pj_wkt1_generated_parser.c.tmp $(top_srcdir)/src/pj_wkt1_generated_parser.c
+
install-exec-local:
rm -f $(DESTDIR)$(bindir)/invproj$(EXEEXT)
diff --git a/src/c_api.cpp b/src/c_api.cpp
index 8140f3b3..d0b5d720 100644
--- a/src/c_api.cpp
+++ b/src/c_api.cpp
@@ -392,6 +392,28 @@ PJ_OBJ *proj_obj_create_from_user_input(PJ_CONTEXT *ctx, const char *text,
// ---------------------------------------------------------------------------
+template <class T> static PROJ_STRING_LIST to_string_list(T &&set) {
+ auto ret = new char *[set.size() + 1];
+ size_t i = 0;
+ for (const auto &str : set) {
+ try {
+ ret[i] = new char[str.size() + 1];
+ } catch (const std::exception &) {
+ while (--i > 0) {
+ delete[] ret[i];
+ }
+ delete[] ret;
+ throw;
+ }
+ std::memcpy(ret[i], str.c_str(), str.size() + 1);
+ i++;
+ }
+ ret[i] = nullptr;
+ return ret;
+}
+
+// ---------------------------------------------------------------------------
+
/** \brief Instanciate an object from a WKT string.
*
* This function calls osgeo::proj::io::WKTParser::createFromWKT()
@@ -401,28 +423,97 @@ PJ_OBJ *proj_obj_create_from_user_input(PJ_CONTEXT *ctx, const char *text,
*
* @param ctx PROJ context, or NULL for default context
* @param wkt WKT string (must not be NULL)
- * @param options should be set to NULL for now
+ * @param options null-terminated list of options, or NULL. Currently
+ * supported options are:
+ * <ul>
+ * <li>STRICT=YES/NO. Defaults to NO. When set to YES, strict validation will
+ * be enabled.</li>
+ * </ul>
+ * @param out_warnings Pointer to a PROJ_STRING_LIST object, or NULL.
+ * If provided, *out_warnings will contain a list of warnings, typically for
+ * non recognized projection method or parameters. It must be freed with
+ * proj_string_list_destroy().
+ * @param out_grammar_errors Pointer to a PROJ_STRING_LIST object, or NULL.
+ * If provided, *out_grammar_errors will contain a list of errors regarding the
+ * WKT grammaer. It must be freed with proj_string_list_destroy().
* @return Object that must be unreferenced with proj_obj_destroy(), or NULL in
* case of error.
*/
PJ_OBJ *proj_obj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt,
- const char *const *options) {
+ const char *const *options,
+ PROJ_STRING_LIST *out_warnings,
+ PROJ_STRING_LIST *out_grammar_errors) {
SANITIZE_CTX(ctx);
assert(wkt);
- (void)options;
+
+ if (out_warnings) {
+ *out_warnings = nullptr;
+ }
+ if (out_grammar_errors) {
+ *out_grammar_errors = nullptr;
+ }
+
try {
WKTParser parser;
auto dbContext = getDBcontextNoException(ctx, __FUNCTION__);
if (dbContext) {
parser.attachDatabaseContext(NN_NO_CHECK(dbContext));
}
- auto identifiedObject = nn_dynamic_pointer_cast<IdentifiedObject>(
+ for (auto iter = options; iter && iter[0]; ++iter) {
+ const char *value;
+ if ((value = getOptionValue(*iter, "STRICT="))) {
+ parser.setStrict(ci_equal(value, "YES"));
+ } else {
+ std::string msg("Unknown option :");
+ msg += *iter;
+ proj_log_error(ctx, __FUNCTION__, msg.c_str());
+ return nullptr;
+ }
+ }
+ auto obj = nn_dynamic_pointer_cast<IdentifiedObject>(
parser.createFromWKT(wkt));
- if (identifiedObject) {
- return PJ_OBJ::create(NN_NO_CHECK(identifiedObject));
+
+ if (out_grammar_errors) {
+ auto warnings = parser.warningList();
+ if (!warnings.empty()) {
+ *out_grammar_errors = to_string_list(warnings);
+ }
+ }
+
+ if (obj && out_warnings) {
+ auto derivedCRS = dynamic_cast<const crs::DerivedCRS *>(obj.get());
+ if (derivedCRS) {
+ auto warnings =
+ derivedCRS->derivingConversionRef()->validateParameters();
+ if (!warnings.empty()) {
+ *out_warnings = to_string_list(warnings);
+ }
+ } else {
+ auto singleOp =
+ dynamic_cast<const operation::SingleOperation *>(obj.get());
+ if (singleOp) {
+ auto warnings = singleOp->validateParameters();
+ if (!warnings.empty()) {
+ *out_warnings = to_string_list(warnings);
+ }
+ }
+ }
+ }
+
+ if (obj) {
+ return PJ_OBJ::create(NN_NO_CHECK(obj));
}
} catch (const std::exception &e) {
- proj_log_error(ctx, __FUNCTION__, e.what());
+ if (out_grammar_errors) {
+ std::list<std::string> exc{e.what()};
+ try {
+ *out_grammar_errors = to_string_list(exc);
+ } catch (const std::exception &) {
+ proj_log_error(ctx, __FUNCTION__, e.what());
+ }
+ } else {
+ proj_log_error(ctx, __FUNCTION__, e.what());
+ }
}
return nullptr;
}
@@ -1832,20 +1923,6 @@ void proj_int_list_destroy(int *list) { delete[] list; }
// ---------------------------------------------------------------------------
-static PROJ_STRING_LIST set_to_string_list(std::set<std::string> &&set) {
- auto ret = new char *[set.size() + 1];
- size_t i = 0;
- for (const auto &str : set) {
- ret[i] = new char[str.size() + 1];
- std::memcpy(ret[i], str.c_str(), str.size() + 1);
- i++;
- }
- ret[i] = nullptr;
- return ret;
-}
-
-// ---------------------------------------------------------------------------
-
/** \brief Return the list of authorities used in the database.
*
* The returned list is NULL terminated and must be freed with
@@ -1859,7 +1936,7 @@ static PROJ_STRING_LIST set_to_string_list(std::set<std::string> &&set) {
PROJ_STRING_LIST proj_get_authorities_from_database(PJ_CONTEXT *ctx) {
SANITIZE_CTX(ctx);
try {
- return set_to_string_list(getDBcontext(ctx)->getAuthorities());
+ return to_string_list(getDBcontext(ctx)->getAuthorities());
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
@@ -1894,7 +1971,7 @@ PROJ_STRING_LIST proj_get_codes_from_database(PJ_CONTEXT *ctx,
if (!valid) {
return nullptr;
}
- return set_to_string_list(
+ return to_string_list(
factory->getAuthorityCodes(typeInternal, allow_deprecated != 0));
} catch (const std::exception &e) {
diff --git a/src/io.cpp b/src/io.cpp
index 65921019..79f8ae5e 100644
--- a/src/io.cpp
+++ b/src/io.cpp
@@ -60,6 +60,8 @@
#include "proj_constants.h"
+#include "pj_wkt1_parser.h"
+
// PROJ include order is sensitive
// clang-format off
#include "proj.h"
@@ -1125,7 +1127,7 @@ std::string WKTNode::toString() const {
//! @cond Doxygen_Suppress
struct WKTParser::Private {
bool strict_ = true;
- std::vector<std::string> warningList_{};
+ std::list<std::string> warningList_{};
std::vector<double> toWGS84Parameters_{};
std::string datumPROJ4Grids_{};
bool esriStyle_ = false;
@@ -1321,7 +1323,7 @@ WKTParser &WKTParser::setStrict(bool strict) {
*
* \note The list might be non-empty only is setStrict(false) has been called.
*/
-std::vector<std::string> WKTParser::warningList() const {
+std::list<std::string> WKTParser::warningList() const {
return d->warningList_;
}
@@ -4205,8 +4207,10 @@ BaseObjectNNPtr createFromUserInput(const std::string &text,
for (const auto &wktConstants : WKTConstants::constants()) {
if (ci_starts_with(text, wktConstants)) {
- return WKTParser().attachDatabaseContext(dbContext).createFromWKT(
- text);
+ return WKTParser()
+ .attachDatabaseContext(dbContext)
+ .setStrict(false)
+ .createFromWKT(text);
}
}
const char *textWithoutPlusPrefix = text.c_str();
@@ -4339,11 +4343,32 @@ BaseObjectNNPtr createFromUserInput(const std::string &text,
// ---------------------------------------------------------------------------
/** \brief Instanciate a sub-class of BaseObject from a WKT string.
+ *
+ * By default, validation is strict (to the extent of the checks that are
+ * actually implemented. Currently only WKT1 strict grammar is checked), and
+ * any issue detected will cause an exception to be thrown, unless
+ * setStrict(false) is called priorly.
+ *
+ * In non-strict mode, non-fatal issues will be recovered and simply listed
+ * in warningList(). This does not prevent more severe errors to cause an
+ * exception to be thrown.
+ *
* @throw ParsingException
*/
BaseObjectNNPtr WKTParser::createFromWKT(const std::string &wkt) {
WKTNodeNNPtr root = WKTNode::createFrom(wkt);
- return d->build(root);
+ auto obj = d->build(root);
+
+ const auto dialect = guessDialect(wkt);
+ if (dialect == WKTGuessedDialect::WKT1_GDAL ||
+ dialect == WKTGuessedDialect::WKT1_ESRI) {
+ auto errorMsg = pj_wkt1_parse(wkt);
+ if (!errorMsg.empty()) {
+ d->emitRecoverableAssertion(errorMsg);
+ }
+ }
+
+ return obj;
}
// ---------------------------------------------------------------------------
diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake
index 9e6f51fd..9eb75c0b 100644
--- a/src/lib_proj.cmake
+++ b/src/lib_proj.cmake
@@ -244,6 +244,7 @@ SET(SRC_LIBPROJ_CORE
rtodms.c
vector1.c
pj_strtod.c
+ pj_wkt1_generated_parser.c
${CMAKE_CURRENT_BINARY_DIR}/proj_config.h
)
@@ -260,6 +261,7 @@ set(SRC_LIBPROJ_CPP
internal.cpp
factory.cpp
c_api.cpp
+ pj_wkt1_parser.cpp
)
set(HEADERS_LIBPROJ
diff --git a/src/pj_wkt1_generated_parser.c b/src/pj_wkt1_generated_parser.c
new file mode 100644
index 00000000..91d5e60d
--- /dev/null
+++ b/src/pj_wkt1_generated_parser.c
@@ -0,0 +1,1664 @@
+/* A Bison parser, made by GNU Bison 3.0.4. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015 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 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 <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "3.0.4"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names. */
+#define yyparse pj_wkt1_parse
+#define yylex pj_wkt1_lex
+#define yyerror pj_wkt1_error
+#define yydebug pj_wkt1_debug
+#define yynerrs pj_wkt1_nerrs
+
+
+/* Copy the first part of user declarations. */
+
+
+/******************************************************************************
+ * Project: PROJ
+ * Purpose: WKT1 parser grammar
+ * Author: Even Rouault, <even.rouault at spatialys.com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2013-2018 Even Rouault, <even.rouault at spatialys.com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "pj_wkt1_parser.h"
+
+
+
+
+# ifndef YY_NULLPTR
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "pj_wkt1_generated_parser.h". */
+#ifndef YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED
+# define YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int pj_wkt1_debug;
+#endif
+
+/* Token type. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ END = 0,
+ T_PARAM_MT = 258,
+ T_CONCAT_MT = 259,
+ T_INVERSE_MT = 260,
+ T_PASSTHROUGH_MT = 261,
+ T_PROJCS = 262,
+ T_PROJECTION = 263,
+ T_GEOGCS = 264,
+ T_DATUM = 265,
+ T_SPHEROID = 266,
+ T_PRIMEM = 267,
+ T_UNIT = 268,
+ T_GEOCCS = 269,
+ T_AUTHORITY = 270,
+ T_VERT_CS = 271,
+ T_VERT_DATUM = 272,
+ T_COMPD_CS = 273,
+ T_AXIS = 274,
+ T_TOWGS84 = 275,
+ T_FITTED_CS = 276,
+ T_LOCAL_CS = 277,
+ T_LOCAL_DATUM = 278,
+ T_PARAMETER = 279,
+ T_EXTENSION = 280,
+ T_STRING = 281,
+ T_NUMBER = 282,
+ T_IDENTIFIER = 283
+ };
+#endif
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+
+int pj_wkt1_parse (pj_wkt1_parse_context *context);
+
+#endif /* !YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED */
+
+/* Copy the second part of user declarations. */
+
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__ \
+ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
+ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+# define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+# define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+# define _Noreturn __declspec (noreturn)
+# else
+# define _Noreturn YY_ATTRIBUTE ((__noreturn__))
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 28
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 215
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 34
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 66
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 99
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 257
+
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+ by yylex, with out-of-bounds checking. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 283
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, without out-of-bounds checking. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 30, 32, 2, 2, 33, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 29, 2, 31, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 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
+};
+
+#if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 76, 76, 88, 88, 91, 94, 94, 97, 97,
+ 97, 97, 100, 103, 105, 106, 109, 111, 112, 115,
+ 118, 122, 127, 127, 127, 127, 127, 127, 130, 130,
+ 134, 138, 139, 142, 143, 145, 146, 147, 148, 150,
+ 151, 154, 157, 160, 164, 166, 167, 168, 169, 172,
+ 176, 179, 182, 185, 188, 191, 194, 197, 200, 203,
+ 204, 205, 206, 209, 212, 215, 217, 218, 219, 222,
+ 224, 225, 226, 229, 232, 235, 238, 240, 243, 248,
+ 251, 253, 256, 259, 262, 265, 268, 271, 274, 277,
+ 280, 283, 286, 289, 292, 294, 296, 297, 298, 301
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 1
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "\"end of string\"", "error", "$undefined", "\"PARAM_MT\"",
+ "\"CONCAT_MT\"", "\"INVERSE_MT\"", "\"PASSTHROUGH_MT\"", "\"PROJCS\"",
+ "\"PROJECTION\"", "\"GEOGCS\"", "\"DATUM\"", "\"SPHEROID\"",
+ "\"PRIMEM\"", "\"UNIT\"", "\"GEOCCS\"", "\"AUTHORITY\"", "\"VERT_CS\"",
+ "\"VERT_DATUM\"", "\"COMPD_CS\"", "\"AXIS\"", "\"TOWGS84\"",
+ "\"FITTED_CS\"", "\"LOCAL_CS\"", "\"LOCAL_DATUM\"", "\"PARAMETER\"",
+ "\"EXTENSION\"", "\"string\"", "\"number\"", "\"identifier\"", "'['",
+ "'('", "']'", "')'", "','", "$accept", "input", "begin_node",
+ "begin_node_name", "end_node", "math_transform", "param_mt", "parameter",
+ "opt_parameter_list", "concat_mt", "opt_math_transform_list", "inv_mt",
+ "passthrough_mt", "integer", "coordinate_system", "horz_cs",
+ "projected_cs", "opt_parameter_list_linear_unit",
+ "parameter_list_linear_unit", "opt_twin_axis_extension_authority",
+ "opt_authority", "extension", "projection", "geographic_cs", "datum",
+ "opt_towgs84_authority_extension", "spheroid", "semi_major_axis",
+ "inverse_flattening", "prime_meridian", "longitude", "angular_unit",
+ "linear_unit", "unit", "conversion_factor", "geocentric_cs",
+ "opt_three_axis_extension_authority", "three_axis", "authority",
+ "vert_cs", "opt_axis_authority", "vert_datum", "opt_extension_authority",
+ "datum_type", "compd_cs", "head_cs", "tail_cs", "twin_axis", "axis",
+ "towgs84", "towgs84_parameters", "three_parameters", "seven_parameters",
+ "dx", "dy", "dz", "ex", "ey", "ez", "ppm", "fitted_cs", "to_base",
+ "base_cs", "local_cs", "opt_axis_list_authority", "local_datum", YY_NULLPTR
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+ (internal) symbol number NUM (which must be that of a token). */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 91,
+ 40, 93, 41, 44
+};
+# endif
+
+#define YYPACT_NINF -127
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-127)))
+
+#define YYTABLE_NINF -1
+
+#define yytable_value_is_error(Yytable_value) \
+ 0
+
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int16 yypact[] =
+{
+ 136, 2, 2, 2, 2, 2, 2, 2, 26, -127,
+ -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,
+ 11, 5, 18, 32, 36, 40, 42, 53, -127, -127,
+ 35, 66, 66, 61, 136, 85, -127, -127, 59, -127,
+ 67, 2, 68, 69, 2, 70, -127, 72, 2, 2,
+ 2, 2, -127, -127, -127, -127, -127, 76, 2, 77,
+ 84, 79, 87, 87, 82, 105, 136, 88, 85, 85,
+ 93, 136, 89, 105, 2, 90, 113, 2, 95, 96,
+ 103, 2, 98, -127, -127, 99, 109, 25, 101, 25,
+ -127, 107, -127, 25, 103, 111, 114, 1, 2, 115,
+ 120, 105, 105, -127, 99, 122, 14, 25, 34, 25,
+ 2, 88, -127, 85, 25, -127, 85, -127, 114, 119,
+ 141, 25, 126, 127, -127, -127, 128, 15, 25, 135,
+ 127, -127, 130, 25, 137, 2, 2, -127, 114, -127,
+ 2, 114, -127, -127, 132, -127, 101, -127, 25, 25,
+ 133, -127, -127, 1, 33, 25, 140, 2, 114, -127,
+ 99, -127, -127, 114, 25, 33, 25, -127, -127, 114,
+ 138, 139, -127, 142, -127, 143, -127, -127, -127, 14,
+ 25, -127, -127, 114, -127, 99, 144, -127, -127, 145,
+ 146, -127, -127, 25, -127, 114, 99, -127, 147, -127,
+ 25, 148, 151, 150, 25, -127, 133, -127, -127, -127,
+ 119, 154, -127, 25, -127, -127, 149, -127, -127, -127,
+ 119, -127, 25, 25, 25, -127, -127, -127, -127, 114,
+ -127, 156, 153, -127, -127, -127, 25, -127, 155, 119,
+ -127, 157, -127, -127, 158, 160, -127, 159, 162, -127,
+ 161, 163, -127, 164, 166, -127, -127
+};
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+ 22, 29, 28, 23, 24, 25, 26, 27, 3, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 5,
+ 0, 0, 0, 0, 0, 0, 6, 7, 0, 95,
+ 0, 0, 0, 0, 0, 0, 75, 0, 0, 0,
+ 0, 0, 92, 8, 9, 10, 11, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 14, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 66, 55, 76, 70, 0, 0, 17, 0,
+ 21, 0, 93, 0, 0, 0, 39, 0, 0, 45,
+ 0, 0, 0, 73, 70, 0, 0, 0, 0, 0,
+ 0, 14, 12, 0, 0, 19, 0, 91, 39, 0,
+ 0, 0, 0, 35, 32, 31, 0, 0, 0, 0,
+ 35, 54, 59, 0, 0, 0, 0, 68, 39, 65,
+ 0, 39, 72, 74, 0, 15, 17, 16, 0, 0,
+ 96, 40, 42, 0, 0, 0, 0, 0, 39, 48,
+ 70, 44, 53, 39, 0, 0, 0, 69, 57, 39,
+ 0, 0, 67, 0, 71, 0, 18, 20, 99, 0,
+ 0, 33, 34, 39, 38, 70, 0, 30, 50, 0,
+ 0, 47, 46, 0, 43, 39, 70, 62, 0, 58,
+ 0, 0, 0, 0, 0, 97, 96, 94, 37, 36,
+ 0, 0, 84, 0, 81, 80, 0, 52, 61, 60,
+ 0, 56, 0, 0, 0, 13, 98, 77, 51, 39,
+ 79, 0, 0, 64, 78, 41, 0, 85, 0, 0,
+ 49, 0, 63, 86, 82, 0, 87, 0, 0, 88,
+ 0, 0, 89, 0, 0, 90, 83
+};
+
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -127, -127, -46, 6, -87, -50, -127, 83, 57, -127,
+ 49, -127, -127, -127, -11, -127, -127, -127, 43, 71,
+ -44, -126, -127, 168, 167, -127, -127, -127, -127, 152,
+ -127, -127, -81, -56, -127, -127, -127, -127, -84, -127,
+ -127, -127, -89, 106, -127, -127, -127, -127, -112, -127,
+ -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,
+ -127, -127, -127, -127, -4, -127
+};
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 8, 20, 21, 39, 52, 53, 122, 87, 54,
+ 114, 55, 56, 91, 9, 10, 11, 123, 124, 155,
+ 121, 141, 75, 12, 42, 128, 99, 189, 229, 78,
+ 163, 130, 82, 83, 169, 13, 166, 196, 137, 14,
+ 107, 45, 109, 104, 15, 47, 85, 185, 138, 160,
+ 213, 214, 215, 216, 238, 244, 247, 250, 253, 256,
+ 16, 57, 93, 17, 180, 59
+};
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_uint8 yytable[] =
+{
+ 112, 158, 115, 68, 69, 70, 117, 150, 22, 23,
+ 24, 25, 26, 27, 81, 133, 125, 95, 88, 89,
+ 139, 132, 143, 46, 142, 110, 28, 147, 183, 135,
+ 135, 18, 19, 136, 152, 157, 151, 29, 30, 195,
+ 140, 161, 186, 159, 2, 131, 167, 61, 135, 135,
+ 64, 31, 136, 198, 67, 84, 36, 37, 140, 140,
+ 92, 177, 178, 146, 72, 32, 148, 206, 187, 33,
+ 184, 192, 182, 34, 149, 35, 41, 194, 44, 199,
+ 96, 197, 58, 100, 36, 37, 38, 105, 48, 49,
+ 50, 51, 74, 207, 172, 205, 209, 174, 227, 77,
+ 60, 62, 63, 65, 126, 66, 217, 219, 232, 71,
+ 73, 190, 76, 221, 191, 80, 144, 225, 81, 193,
+ 90, 86, 94, 97, 98, 200, 230, 242, 101, 102,
+ 103, 106, 108, 110, 113, 233, 234, 235, 136, 208,
+ 116, 170, 171, 1, 119, 2, 173, 120, 127, 240,
+ 3, 218, 4, 129, 5, 134, 135, 6, 7, 153,
+ 154, 156, 162, 165, 168, 175, 179, 188, 145, 111,
+ 204, 201, 202, 212, 222, 203, 224, 210, 211, 223,
+ 220, 228, 231, 237, 243, 236, 239, 246, 241, 249,
+ 252, 245, 248, 255, 251, 176, 181, 254, 40, 43,
+ 118, 164, 226, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 79
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 87, 127, 89, 49, 50, 51, 93, 119, 2, 3,
+ 4, 5, 6, 7, 13, 104, 97, 73, 68, 69,
+ 107, 102, 109, 34, 108, 24, 0, 114, 154, 15,
+ 15, 29, 30, 19, 121, 20, 120, 26, 33, 165,
+ 25, 128, 154, 127, 9, 101, 133, 41, 15, 15,
+ 44, 33, 19, 165, 48, 66, 31, 32, 25, 25,
+ 71, 148, 149, 113, 58, 33, 116, 179, 155, 33,
+ 154, 160, 153, 33, 118, 33, 10, 164, 17, 166,
+ 74, 165, 23, 77, 31, 32, 33, 81, 3, 4,
+ 5, 6, 8, 180, 138, 179, 185, 141, 210, 12,
+ 33, 33, 33, 33, 98, 33, 193, 196, 220, 33,
+ 33, 157, 33, 200, 158, 33, 110, 204, 13, 163,
+ 27, 33, 33, 33, 11, 169, 213, 239, 33, 33,
+ 27, 33, 33, 24, 33, 222, 223, 224, 19, 183,
+ 33, 135, 136, 7, 33, 9, 140, 33, 33, 236,
+ 14, 195, 16, 33, 18, 33, 15, 21, 22, 33,
+ 33, 33, 27, 33, 27, 33, 33, 27, 111, 86,
+ 27, 33, 33, 27, 26, 33, 26, 33, 33, 28,
+ 33, 27, 33, 27, 27, 229, 33, 27, 33, 27,
+ 27, 33, 33, 27, 33, 146, 153, 33, 30, 32,
+ 94, 130, 206, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 63
+};
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 7, 9, 14, 16, 18, 21, 22, 35, 48,
+ 49, 50, 57, 69, 73, 78, 94, 97, 29, 30,
+ 36, 37, 37, 37, 37, 37, 37, 37, 0, 26,
+ 33, 33, 33, 33, 33, 33, 31, 32, 33, 38,
+ 57, 10, 58, 58, 17, 75, 48, 79, 3, 4,
+ 5, 6, 39, 40, 43, 45, 46, 95, 23, 99,
+ 33, 37, 33, 33, 37, 33, 33, 37, 36, 36,
+ 36, 33, 37, 33, 8, 56, 33, 12, 63, 63,
+ 33, 13, 66, 67, 48, 80, 33, 42, 39, 39,
+ 27, 47, 48, 96, 33, 67, 37, 33, 11, 60,
+ 37, 33, 33, 27, 77, 37, 33, 74, 33, 76,
+ 24, 41, 38, 33, 44, 38, 33, 38, 77, 33,
+ 33, 54, 41, 51, 52, 66, 37, 33, 59, 33,
+ 65, 67, 66, 76, 33, 15, 19, 72, 82, 38,
+ 25, 55, 72, 38, 37, 42, 39, 38, 39, 54,
+ 82, 72, 38, 33, 33, 53, 33, 20, 55, 72,
+ 83, 38, 27, 64, 53, 33, 70, 38, 27, 68,
+ 37, 37, 54, 37, 54, 33, 44, 38, 38, 33,
+ 98, 52, 66, 55, 72, 81, 82, 38, 27, 61,
+ 36, 54, 76, 54, 38, 55, 71, 72, 82, 38,
+ 54, 33, 33, 33, 27, 72, 82, 38, 54, 76,
+ 33, 33, 27, 84, 85, 86, 87, 38, 54, 76,
+ 33, 38, 26, 28, 26, 38, 98, 82, 27, 62,
+ 38, 33, 82, 38, 38, 38, 54, 27, 88, 33,
+ 38, 33, 82, 27, 89, 33, 27, 90, 33, 27,
+ 91, 33, 27, 92, 33, 27, 93
+};
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 34, 35, 36, 36, 37, 38, 38, 39, 39,
+ 39, 39, 40, 41, 42, 42, 43, 44, 44, 45,
+ 46, 47, 48, 48, 48, 48, 48, 48, 49, 49,
+ 50, 51, 51, 52, 52, 53, 53, 53, 53, 54,
+ 54, 55, 56, 57, 58, 59, 59, 59, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ 70, 70, 70, 71, 72, 73, 74, 74, 74, 75,
+ 76, 76, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97, 97, 98, 98, 98, 99
+};
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 1, 1, 2, 1, 1, 1, 1,
+ 1, 1, 4, 5, 0, 3, 5, 0, 3, 4,
+ 6, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 10, 1, 1, 3, 3, 0, 3, 3, 2, 0,
+ 2, 5, 4, 10, 6, 0, 3, 3, 2, 8,
+ 1, 1, 6, 1, 1, 1, 6, 1, 10, 0,
+ 3, 3, 2, 5, 5, 8, 0, 3, 2, 6,
+ 0, 3, 2, 1, 8, 1, 1, 3, 5, 4,
+ 1, 1, 5, 13, 1, 1, 1, 1, 1, 1,
+ 1, 7, 1, 1, 10, 3, 0, 2, 3, 6
+};
+
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (context, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (0)
+
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value, context); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT. |
+`----------------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, pj_wkt1_parse_context *context)
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ YYUSE (context);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ YYUSE (yytype);
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, pj_wkt1_parse_context *context)
+{
+ YYFPRINTF (yyoutput, "%s %s (",
+ yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, context);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, pj_wkt1_parse_context *context)
+{
+ unsigned long int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr,
+ yystos[yyssp[yyi + 1 - yynrhs]],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ , context);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, Rule, context); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+yystrlen (const char *yystr)
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr && yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, pj_wkt1_parse_context *context)
+{
+ YYUSE (yyvaluep);
+ YYUSE (context);
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yytype);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+int
+yyparse (pj_wkt1_parse_context *context)
+{
+/* The lookahead symbol. */
+int yychar;
+
+
+/* The semantic value of the lookahead symbol. */
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
+YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
+
+ /* Number of syntax errors so far. */
+ int yynerrs;
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ 'yyss': related to states.
+ 'yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = (yytype_int16)yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = yylex (&yylval, context);
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (context, YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (context, yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, context);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+#if 0
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+#endif
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp, context);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (context, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, context);
+ }
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp, context);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ return yyresult;
+}
diff --git a/src/pj_wkt1_generated_parser.h b/src/pj_wkt1_generated_parser.h
new file mode 100644
index 00000000..7bdec61f
--- /dev/null
+++ b/src/pj_wkt1_generated_parser.h
@@ -0,0 +1,89 @@
+/* A Bison parser, made by GNU Bison 3.0.4. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015 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 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 <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED
+# define YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int pj_wkt1_debug;
+#endif
+
+/* Token type. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ END = 0,
+ T_PARAM_MT = 258,
+ T_CONCAT_MT = 259,
+ T_INVERSE_MT = 260,
+ T_PASSTHROUGH_MT = 261,
+ T_PROJCS = 262,
+ T_PROJECTION = 263,
+ T_GEOGCS = 264,
+ T_DATUM = 265,
+ T_SPHEROID = 266,
+ T_PRIMEM = 267,
+ T_UNIT = 268,
+ T_GEOCCS = 269,
+ T_AUTHORITY = 270,
+ T_VERT_CS = 271,
+ T_VERT_DATUM = 272,
+ T_COMPD_CS = 273,
+ T_AXIS = 274,
+ T_TOWGS84 = 275,
+ T_FITTED_CS = 276,
+ T_LOCAL_CS = 277,
+ T_LOCAL_DATUM = 278,
+ T_PARAMETER = 279,
+ T_EXTENSION = 280,
+ T_STRING = 281,
+ T_NUMBER = 282,
+ T_IDENTIFIER = 283
+ };
+#endif
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+
+int pj_wkt1_parse (pj_wkt1_parse_context *context);
+
+#endif /* !YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED */
diff --git a/src/pj_wkt1_grammar.y b/src/pj_wkt1_grammar.y
new file mode 100644
index 00000000..05ae792a
--- /dev/null
+++ b/src/pj_wkt1_grammar.y
@@ -0,0 +1,301 @@
+%{
+/******************************************************************************
+ * Project: PROJ
+ * Purpose: WKT1 parser grammar
+ * Author: Even Rouault, <even.rouault at spatialys.com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2013-2018 Even Rouault, <even.rouault at spatialys.com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "pj_wkt1_parser.h"
+
+%}
+
+%define api.pure
+/* if the next %define is commented out, Bison 2.4 should be sufficient */
+/* but will produce less prettier error messages */
+%define parse.error verbose
+%require "3.0"
+
+%parse-param {pj_wkt1_parse_context *context}
+%lex-param {pj_wkt1_parse_context *context}
+
+%token T_PARAM_MT "PARAM_MT"
+%token T_CONCAT_MT "CONCAT_MT"
+%token T_INVERSE_MT "INVERSE_MT"
+%token T_PASSTHROUGH_MT "PASSTHROUGH_MT"
+%token T_PROJCS "PROJCS"
+%token T_PROJECTION "PROJECTION"
+%token T_GEOGCS "GEOGCS"
+%token T_DATUM "DATUM"
+%token T_SPHEROID "SPHEROID"
+%token T_PRIMEM "PRIMEM"
+%token T_UNIT "UNIT"
+%token T_GEOCCS "GEOCCS"
+%token T_AUTHORITY "AUTHORITY"
+%token T_VERT_CS "VERT_CS"
+%token T_VERT_DATUM "VERT_DATUM"
+%token T_COMPD_CS "COMPD_CS"
+%token T_AXIS "AXIS"
+%token T_TOWGS84 "TOWGS84"
+%token T_FITTED_CS "FITTED_CS"
+%token T_LOCAL_CS "LOCAL_CS"
+%token T_LOCAL_DATUM "LOCAL_DATUM"
+%token T_PARAMETER "PARAMETER"
+
+%token T_EXTENSION "EXTENSION"
+
+%token T_STRING "string"
+%token T_NUMBER "number"
+%token T_IDENTIFIER "identifier"
+
+%token END 0 "end of string"
+
+%%
+
+input:
+ coordinate_system
+
+/* Derived from BNF grammar in OGC 01-009 OpenGIS Implementation */
+/* Coordinate Transformation Services Revision 1.00 */
+/* with the following additions : */
+/* - accept an EXTENSION node at the end of GEOGCS, GEOCCS, PROJCS, COMPD_CS, VERT_DATUM */
+/* - accept 3 parameters in TOWGS84 */
+/* - accept LOCAL_CS["foo"] */
+
+/* 7.1 Math Transform WKT */
+
+begin_node:
+ '[' | '('
+
+begin_node_name:
+ begin_node T_STRING
+
+end_node:
+ ']' | ')'
+
+math_transform:
+ param_mt | concat_mt | inv_mt | passthrough_mt
+
+param_mt:
+ T_PARAM_MT begin_node_name opt_parameter_list end_node
+
+parameter:
+ T_PARAMETER begin_node_name ',' T_NUMBER end_node
+
+opt_parameter_list:
+ | ',' parameter opt_parameter_list
+
+concat_mt:
+ T_CONCAT_MT begin_node math_transform opt_math_transform_list end_node
+
+opt_math_transform_list:
+ | ',' math_transform opt_math_transform_list
+
+inv_mt:
+ T_INVERSE_MT begin_node math_transform end_node
+
+passthrough_mt:
+ T_PASSTHROUGH_MT begin_node integer ',' math_transform end_node
+
+/* FIXME */
+integer:
+ T_NUMBER
+
+/* 7.2 Coordinate System WKT */
+
+coordinate_system:
+ horz_cs | geocentric_cs | vert_cs | compd_cs | fitted_cs | local_cs
+
+horz_cs:
+ geographic_cs | projected_cs
+
+/* opt_extension is an extension of the CT spec */
+projected_cs:
+ T_PROJCS begin_node_name ',' geographic_cs ',' projection ','
+ opt_parameter_list_linear_unit opt_twin_axis_extension_authority end_node
+
+opt_parameter_list_linear_unit:
+ linear_unit
+ | parameter_list_linear_unit
+
+parameter_list_linear_unit:
+ parameter ',' parameter_list_linear_unit
+ | parameter ',' linear_unit
+
+opt_twin_axis_extension_authority:
+ | ',' twin_axis opt_extension_authority
+ | ',' extension opt_authority
+ | ',' authority
+
+opt_authority:
+ | ',' authority
+
+extension:
+ T_EXTENSION begin_node_name ',' T_STRING end_node
+
+projection:
+ T_PROJECTION begin_node_name opt_authority end_node
+
+geographic_cs:
+ T_GEOGCS begin_node_name',' datum ',' prime_meridian ','
+ angular_unit opt_twin_axis_extension_authority end_node
+
+datum:
+ T_DATUM begin_node_name ',' spheroid opt_towgs84_authority_extension end_node
+
+opt_towgs84_authority_extension:
+ | ',' towgs84 opt_extension_authority
+ | ',' extension opt_authority
+ | ',' authority
+
+spheroid:
+ T_SPHEROID begin_node_name ',' semi_major_axis ','
+ inverse_flattening opt_authority end_node
+
+semi_major_axis:
+ T_NUMBER
+
+inverse_flattening:
+ T_NUMBER
+
+prime_meridian:
+ T_PRIMEM begin_node_name ',' longitude opt_authority end_node
+
+longitude:
+ T_NUMBER
+
+angular_unit:
+ unit
+
+linear_unit:
+ unit
+
+unit:
+ T_UNIT begin_node_name ',' conversion_factor opt_authority end_node
+
+conversion_factor:
+ T_NUMBER
+
+geocentric_cs:
+ T_GEOCCS begin_node_name ',' datum ',' prime_meridian ','
+ linear_unit opt_three_axis_extension_authority end_node
+
+opt_three_axis_extension_authority:
+ | ',' three_axis opt_extension_authority
+ | ',' extension opt_authority
+ | ',' authority
+
+three_axis:
+ axis ',' axis ',' axis
+
+authority:
+ T_AUTHORITY begin_node_name ',' T_STRING end_node
+
+vert_cs:
+ T_VERT_CS begin_node_name ',' vert_datum ',' linear_unit opt_axis_authority end_node
+
+opt_axis_authority:
+ | ',' axis opt_authority
+ | ',' authority
+
+vert_datum:
+ T_VERT_DATUM begin_node_name ',' datum_type opt_extension_authority end_node
+
+opt_extension_authority:
+ | ',' extension opt_authority
+ | ',' authority
+
+datum_type:
+ T_NUMBER
+
+compd_cs:
+ T_COMPD_CS begin_node_name ',' head_cs ',' tail_cs opt_extension_authority end_node
+
+head_cs:
+ coordinate_system
+
+tail_cs:
+ coordinate_system
+
+twin_axis: axis ',' axis
+
+axis:
+ T_AXIS begin_node_name ',' T_IDENTIFIER end_node
+/* Extension of the CT spec */
+/* | T_AXIS '[' T_STRING ',' T_STRING ']'*/
+
+towgs84:
+ T_TOWGS84 begin_node towgs84_parameters end_node
+
+towgs84_parameters:
+ seven_parameters
+/* Extension of the CT spec */
+ | three_parameters
+
+three_parameters:
+ dx ',' dy ',' dz
+
+seven_parameters:
+ dx ',' dy ',' dz ',' ex ',' ey ',' ez ',' ppm
+
+dx:
+ T_NUMBER
+
+dy:
+ T_NUMBER
+
+dz:
+ T_NUMBER
+
+ex:
+ T_NUMBER
+
+ey:
+ T_NUMBER
+
+ez:
+ T_NUMBER
+
+ppm:
+ T_NUMBER
+
+fitted_cs:
+ T_FITTED_CS begin_node_name ',' to_base ',' base_cs end_node
+
+to_base:
+ math_transform
+
+base_cs:
+ coordinate_system
+
+local_cs:
+ T_LOCAL_CS begin_node_name ',' local_datum ',' unit ',' axis opt_axis_list_authority end_node
+/* Extension of the CT spec: accept only name */
+ | T_LOCAL_CS begin_node_name end_node
+
+opt_axis_list_authority:
+ | ',' authority
+ | ',' axis opt_axis_list_authority
+
+local_datum:
+ T_LOCAL_DATUM begin_node_name ',' datum_type opt_authority end_node
diff --git a/src/pj_wkt1_parser.cpp b/src/pj_wkt1_parser.cpp
new file mode 100644
index 00000000..7ddd595a
--- /dev/null
+++ b/src/pj_wkt1_parser.cpp
@@ -0,0 +1,221 @@
+/******************************************************************************
+ * Project: PROJ
+ * Purpose: WKT1 parser grammar
+ * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
+ *
+ ******************************************************************************
+ * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef FROM_PROJ_CPP
+#define FROM_PROJ_CPP
+#endif
+
+#include "proj/internal/internal.hpp"
+
+#include <algorithm>
+#include <cstring>
+#include <string>
+
+#include "pj_wkt1_parser.h"
+
+using namespace NS_PROJ::internal;
+
+//! @cond Doxygen_Suppress
+
+// ---------------------------------------------------------------------------
+
+struct pj_wkt1_parse_context {
+ const char *pszInput = nullptr;
+ const char *pszLastSuccess = nullptr;
+ const char *pszNext = nullptr;
+ std::string errorMsg{};
+
+ pj_wkt1_parse_context() = default;
+ pj_wkt1_parse_context(const pj_wkt1_parse_context &) = delete;
+ pj_wkt1_parse_context &operator=(const pj_wkt1_parse_context &) = delete;
+};
+
+// ---------------------------------------------------------------------------
+
+void pj_wkt1_error(pj_wkt1_parse_context *context, const char *msg) {
+ context->errorMsg = "Parsing error : ";
+ context->errorMsg += msg;
+ context->errorMsg += ". Error occurred around:\n";
+
+ std::string ctxtMsg;
+ const int n = static_cast<int>(context->pszLastSuccess - context->pszInput);
+ int start_i = std::max(0, n - 40);
+ for (int i = start_i; i < n + 40 && context->pszInput[i]; i++) {
+ if (context->pszInput[i] == '\r' || context->pszInput[i] == '\n') {
+ if (i > n) {
+ break;
+ } else {
+ ctxtMsg.clear();
+ start_i = i + 1;
+ }
+ } else {
+ ctxtMsg += context->pszInput[i];
+ }
+ }
+ context->errorMsg += ctxtMsg;
+ context->errorMsg += '\n';
+ for (int i = start_i; i < n; i++)
+ context->errorMsg += ' ';
+ context->errorMsg += '^';
+}
+
+// ---------------------------------------------------------------------------
+
+std::string pj_wkt1_parse(const std::string &wkt) {
+ pj_wkt1_parse_context context;
+ context.pszInput = wkt.c_str();
+ context.pszLastSuccess = wkt.c_str();
+ context.pszNext = wkt.c_str();
+ if (pj_wkt1_parse(&context) != 0) {
+ return context.errorMsg;
+ }
+ return std::string();
+}
+
+// ---------------------------------------------------------------------------
+
+typedef struct {
+ const char *pszToken;
+ int nTokenVal;
+} osr_cs_wkt_tokens;
+
+#define PAIR(X) \
+ { #X, T_##X }
+
+static const osr_cs_wkt_tokens tokens[] = {
+ PAIR(PARAM_MT), PAIR(PARAMETER), PAIR(CONCAT_MT), PAIR(INVERSE_MT),
+ PAIR(PASSTHROUGH_MT),
+
+ PAIR(PROJCS), PAIR(PROJECTION), PAIR(GEOGCS), PAIR(DATUM),
+ PAIR(SPHEROID), PAIR(PRIMEM), PAIR(UNIT), PAIR(GEOCCS),
+ PAIR(AUTHORITY), PAIR(VERT_CS), PAIR(VERT_DATUM), PAIR(COMPD_CS),
+ PAIR(AXIS), PAIR(TOWGS84), PAIR(FITTED_CS), PAIR(LOCAL_CS),
+ PAIR(LOCAL_DATUM),
+
+ PAIR(EXTENSION)};
+
+// ---------------------------------------------------------------------------
+
+int pj_wkt1_lex(YYSTYPE * /*pNode */, pj_wkt1_parse_context *context) {
+ size_t i;
+ const char *pszInput = context->pszNext;
+
+ /* -------------------------------------------------------------------- */
+ /* Skip white space. */
+ /* -------------------------------------------------------------------- */
+ while (*pszInput == ' ' || *pszInput == '\t' || *pszInput == 10 ||
+ *pszInput == 13)
+ pszInput++;
+
+ context->pszLastSuccess = pszInput;
+
+ if (*pszInput == '\0') {
+ context->pszNext = pszInput;
+ return EOF;
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Recognize node names. */
+ /* -------------------------------------------------------------------- */
+ for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) {
+ if (ci_starts_with(pszInput, tokens[i].pszToken)) {
+ context->pszNext = pszInput + strlen(tokens[i].pszToken);
+ return tokens[i].nTokenVal;
+ }
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Recognize double quoted strings. */
+ /* -------------------------------------------------------------------- */
+ if (*pszInput == '"') {
+ pszInput++;
+ while (*pszInput != '\0' && *pszInput != '"')
+ pszInput++;
+ if (*pszInput == '\0') {
+ context->pszNext = pszInput;
+ return EOF;
+ }
+ context->pszNext = pszInput + 1;
+ return T_STRING;
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Recognize numerical values. */
+ /* -------------------------------------------------------------------- */
+
+ if (((*pszInput == '-' || *pszInput == '+') && pszInput[1] >= '0' &&
+ pszInput[1] <= '9') ||
+ (*pszInput >= '0' && *pszInput <= '9')) {
+ if (*pszInput == '-' || *pszInput == '+')
+ pszInput++;
+
+ // collect non-decimal part of number
+ while (*pszInput >= '0' && *pszInput <= '9')
+ pszInput++;
+
+ // collect decimal places.
+ if (*pszInput == '.') {
+ pszInput++;
+ while (*pszInput >= '0' && *pszInput <= '9')
+ pszInput++;
+ }
+
+ // collect exponent
+ if (*pszInput == 'e' || *pszInput == 'E') {
+ pszInput++;
+ if (*pszInput == '-' || *pszInput == '+')
+ pszInput++;
+ while (*pszInput >= '0' && *pszInput <= '9')
+ pszInput++;
+ }
+
+ context->pszNext = pszInput;
+
+ return T_NUMBER;
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Recognize identifiers. */
+ /* -------------------------------------------------------------------- */
+ if ((*pszInput >= 'A' && *pszInput <= 'Z') ||
+ (*pszInput >= 'a' && *pszInput <= 'z')) {
+ pszInput++;
+ while ((*pszInput >= 'A' && *pszInput <= 'Z') ||
+ (*pszInput >= 'a' && *pszInput <= 'z'))
+ pszInput++;
+ context->pszNext = pszInput;
+ return T_IDENTIFIER;
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Handle special tokens. */
+ /* -------------------------------------------------------------------- */
+ context->pszNext = pszInput + 1;
+ return *pszInput;
+}
+
+//! @endcond
diff --git a/src/pj_wkt1_parser.h b/src/pj_wkt1_parser.h
new file mode 100644
index 00000000..f8f7c841
--- /dev/null
+++ b/src/pj_wkt1_parser.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+ * Project: PROJ
+ * Purpose: WKT1 parser grammar
+ * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
+ *
+ ******************************************************************************
+ * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef PJ_WKT1_PARSER_H_INCLUDED
+#define PJ_WKT1_PARSER_H_INCLUDED
+
+#ifndef DOXYGEN_SKIP
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pj_wkt1_parse_context pj_wkt1_parse_context;
+
+#include "pj_wkt1_generated_parser.h"
+
+void pj_wkt1_error( pj_wkt1_parse_context *context, const char *msg );
+int pj_wkt1_lex(YYSTYPE* pNode, pj_wkt1_parse_context *context);
+int pj_wkt1_parse(pj_wkt1_parse_context *context);
+
+#ifdef __cplusplus
+}
+
+std::string pj_wkt1_parse(const std::string& wkt);
+
+#endif
+
+#endif /* #ifndef DOXYGEN_SKIP */
+
+#endif /* PJ_WKT1_PARSER_H_INCLUDED */
diff --git a/src/proj.h b/src/proj.h
index 3ea1ee68..5c0e8fdc 100644
--- a/src/proj.h
+++ b/src/proj.h
@@ -456,6 +456,11 @@ typedef struct PJ_OBJ PJ_OBJ;
typedef struct PJ_OBJ_LIST PJ_OBJ_LIST;
/*! @endcond */
+/** \brief Type representing a NULL terminated list of NUL-terminate strings. */
+typedef char **PROJ_STRING_LIST;
+
+void PROJ_DLL proj_string_list_destroy(PROJ_STRING_LIST list);
+
int PROJ_DLL proj_context_set_database_path(PJ_CONTEXT *ctx,
const char *dbPath,
const char *const *auxDbPaths,
@@ -494,7 +499,9 @@ PJ_OBJ PROJ_DLL *proj_obj_create_from_user_input(PJ_CONTEXT *ctx,
const char* const *options);
PJ_OBJ PROJ_DLL *proj_obj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt,
- const char* const *options);
+ const char* const *options,
+ PROJ_STRING_LIST *out_warnings,
+ PROJ_STRING_LIST *out_grammar_errors);
PJ_OBJ PROJ_DLL *proj_obj_create_from_proj_string(PJ_CONTEXT *ctx,
const char *proj_string,
@@ -677,9 +684,6 @@ void PROJ_DLL proj_int_list_destroy(int* list);
/* ------------------------------------------------------------------------- */
-/** \brief Type representing a NULL terminated list of NUL-terminate strings. */
-typedef char **PROJ_STRING_LIST;
-
PROJ_STRING_LIST PROJ_DLL proj_get_authorities_from_database(PJ_CONTEXT *ctx);
PROJ_STRING_LIST PROJ_DLL proj_get_codes_from_database(PJ_CONTEXT *ctx,
@@ -687,8 +691,6 @@ PROJ_STRING_LIST PROJ_DLL proj_get_codes_from_database(PJ_CONTEXT *ctx,
PJ_OBJ_TYPE type,
int allow_deprecated);
-void PROJ_DLL proj_string_list_destroy(PROJ_STRING_LIST list);
-
/* ------------------------------------------------------------------------- */
diff --git a/src/projinfo.cpp b/src/projinfo.cpp
index d6fa37bc..cf666b4d 100644
--- a/src/projinfo.cpp
+++ b/src/projinfo.cpp
@@ -136,8 +136,8 @@ static std::string c_ify_string(const std::string &str) {
static BaseObjectNNPtr buildObject(DatabaseContextPtr dbContext,
const std::string &user_string,
bool kindIsCRS, const std::string &context,
- bool buildBoundCRSToWGS84,
- bool allowPivots) {
+ bool buildBoundCRSToWGS84, bool allowPivots,
+ bool quiet) {
BaseObjectPtr obj;
std::string l_user_string(user_string);
@@ -182,7 +182,24 @@ static BaseObjectNNPtr buildObject(DatabaseContextPtr dbContext,
l_user_string.find("\\\"") != std::string::npos) {
l_user_string = un_c_ify_string(l_user_string);
}
- obj = createFromUserInput(l_user_string, dbContext).as_nullable();
+ WKTParser wktParser;
+ if (wktParser.guessDialect(l_user_string) !=
+ WKTParser::WKTGuessedDialect::NOT_WKT) {
+ wktParser.setStrict(false);
+ wktParser.attachDatabaseContext(dbContext);
+ obj = wktParser.createFromWKT(l_user_string).as_nullable();
+ if (!quiet) {
+ auto warnings = wktParser.warningList();
+ if (!warnings.empty()) {
+ for (const auto &str : warnings) {
+ std::cerr << "Warning: " << str << std::endl;
+ }
+ }
+ }
+ } else {
+ obj =
+ createFromUserInput(l_user_string, dbContext).as_nullable();
+ }
}
} catch (const std::exception &e) {
std::cerr << context << ": parsing of user string failed: " << e.what()
@@ -509,16 +526,16 @@ static void outputOperations(
const std::vector<std::pair<std::string, std::string>> &pivots,
const std::string &authority, bool usePROJGridAlternatives,
bool showSuperseded, const OutputOptions &outputOpt, bool summary) {
- auto sourceObj =
- buildObject(dbContext, sourceCRSStr, true, "source CRS", false, false);
+ auto sourceObj = buildObject(dbContext, sourceCRSStr, true, "source CRS",
+ false, false, outputOpt.quiet);
auto sourceCRS = nn_dynamic_pointer_cast<CRS>(sourceObj);
if (!sourceCRS) {
std::cerr << "source CRS string is not a CRS" << std::endl;
std::exit(1);
}
- auto targetObj =
- buildObject(dbContext, targetCRSStr, true, "target CRS", false, false);
+ auto targetObj = buildObject(dbContext, targetCRSStr, true, "target CRS",
+ false, false, outputOpt.quiet);
auto targetCRS = nn_dynamic_pointer_cast<CRS>(targetObj);
if (!targetCRS) {
std::cerr << "target CRS string is not a CRS" << std::endl;
@@ -910,7 +927,8 @@ int main(int argc, char **argv) {
if (!user_string.empty()) {
auto obj(buildObject(dbContext, user_string, kindIsCRS, "input string",
- buildBoundCRSToWGS84, allowPivots));
+ buildBoundCRSToWGS84, allowPivots,
+ outputOpt.quiet));
if (guessDialect) {
auto dialect = WKTParser().guessDialect(user_string);
std::cout << "Guessed WKT dialect: ";
diff --git a/test/cli/testprojinfo b/test/cli/testprojinfo
index ea0dcc2d..bae38482 100755
--- a/test/cli/testprojinfo
+++ b/test/cli/testprojinfo
@@ -78,6 +78,10 @@ echo "Testing deprecated CRS: projinfo EPSG:26591" >> ${OUT}
$EXE EPSG:26591 >>${OUT} 2>&1
echo "" >>${OUT}
+echo "Testing non compliant WKT1" >> ${OUT}
+$EXE 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563]],UNIT["degree",0.0174532925199433]]' >>${OUT} 2>&1
+echo "" >>${OUT}
+
# do 'diff' with distribution results
echo "diff ${OUT} with testprojinfo_out.dist"
diff -u ${OUT} ${TEST_CLI_DIR}/testprojinfo_out.dist
diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist
index 40035489..1fd3bbbf 100644
--- a/test/cli/testprojinfo_out.dist
+++ b/test/cli/testprojinfo_out.dist
@@ -523,3 +523,28 @@ PROJCRS["Monte Mario (Rome) / Italy zone 1",
BBOX[36.53,5.94,47.04,12],
ID["EPSG",26591]]
+Testing non compliant WKT1
+Warning: GEOGCS should have a PRIMEM node
+Warning: Parsing error : syntax error, unexpected UNIT, expecting PRIMEM. Error occurred around:
+HEROID["WGS 84",6378137,298.257223563]],UNIT["degree",0.0174532925199433]]
+ ^
+PROJ string:
++proj=pipeline +step +proj=longlat +ellps=WGS84 +step +proj=unitconvert +xy_in=rad +xy_out=deg
+
+WKT2_2015 string:
+GEODCRS["WGS 84",
+ DATUM["World Geodetic System 1984",
+ ELLIPSOID["WGS 84",6378137,298.257223563,
+ LENGTHUNIT["metre",1,
+ ID["EPSG",9001]]]],
+ PRIMEM["Greenwich",0,
+ ANGLEUNIT["degree",0.0174532925199433],
+ ID["EPSG",8901]],
+ CS[ellipsoidal,2],
+ AXIS["longitude",east,
+ ORDER[1],
+ ANGLEUNIT["degree",0.0174532925199433]],
+ AXIS["latitude",north,
+ ORDER[2],
+ ANGLEUNIT["degree",0.0174532925199433]]]
+
diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp
index 7df7442a..37ca076c 100644
--- a/test/unit/test_c_api.cpp
+++ b/test/unit/test_c_api.cpp
@@ -166,14 +166,128 @@ TEST_F(CApi, proj_obj_create_from_user_input) {
TEST_F(CApi, proj_obj_create_from_wkt) {
proj_obj_destroy(nullptr);
- EXPECT_EQ(proj_obj_create_from_wkt(m_ctxt, "invalid", nullptr), nullptr);
- auto obj = proj_obj_create_from_wkt(
- m_ctxt,
- GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
- .c_str(),
- nullptr);
- ObjectKeeper keeper(obj);
- EXPECT_NE(obj, nullptr);
+ {
+ EXPECT_EQ(proj_obj_create_from_wkt(m_ctxt, "invalid", nullptr, nullptr,
+ nullptr),
+ nullptr);
+ }
+ {
+ PROJ_STRING_LIST warningList = nullptr;
+ PROJ_STRING_LIST errorList = nullptr;
+ EXPECT_EQ(proj_obj_create_from_wkt(m_ctxt, "invalid", nullptr,
+ &warningList, &errorList),
+ nullptr);
+ EXPECT_EQ(warningList, nullptr);
+ proj_string_list_destroy(warningList);
+ EXPECT_NE(errorList, nullptr);
+ proj_string_list_destroy(errorList);
+ }
+ {
+ auto obj = proj_obj_create_from_wkt(
+ m_ctxt,
+ GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
+ .c_str(),
+ nullptr, nullptr, nullptr);
+ ObjectKeeper keeper(obj);
+ EXPECT_NE(obj, nullptr);
+ }
+ {
+ auto obj = proj_obj_create_from_wkt(
+ m_ctxt,
+ "GEOGCS[\"WGS 84\",\n"
+ " DATUM[\"WGS_1984\",\n"
+ " SPHEROID[\"WGS 84\",6378137,298.257223563,\"unused\"]],\n"
+ " PRIMEM[\"Greenwich\",0],\n"
+ " UNIT[\"degree\",0.0174532925199433]]",
+ nullptr, nullptr, nullptr);
+ EXPECT_EQ(obj, nullptr);
+ }
+ {
+ PROJ_STRING_LIST warningList = nullptr;
+ PROJ_STRING_LIST errorList = nullptr;
+ auto obj = proj_obj_create_from_wkt(
+ m_ctxt,
+ "GEOGCS[\"WGS 84\",\n"
+ " DATUM[\"WGS_1984\",\n"
+ " SPHEROID[\"WGS 84\",6378137,298.257223563,\"unused\"]],\n"
+ " PRIMEM[\"Greenwich\",0],\n"
+ " UNIT[\"degree\",0.0174532925199433]]",
+ nullptr, &warningList, &errorList);
+ EXPECT_EQ(obj, nullptr);
+ EXPECT_EQ(warningList, nullptr);
+ proj_string_list_destroy(warningList);
+ EXPECT_NE(errorList, nullptr);
+ proj_string_list_destroy(errorList);
+ }
+ {
+ PROJ_STRING_LIST warningList = nullptr;
+ PROJ_STRING_LIST errorList = nullptr;
+ const char *const options[] = {"STRICT=NO", nullptr};
+ auto obj = proj_obj_create_from_wkt(
+ m_ctxt,
+ "GEOGCS[\"WGS 84\",\n"
+ " DATUM[\"WGS_1984\",\n"
+ " SPHEROID[\"WGS 84\",6378137,298.257223563,\"unused\"]],\n"
+ " PRIMEM[\"Greenwich\",0],\n"
+ " UNIT[\"degree\",0.0174532925199433]]",
+ options, &warningList, &errorList);
+ ObjectKeeper keeper(obj);
+ EXPECT_NE(obj, nullptr);
+ EXPECT_EQ(warningList, nullptr);
+ proj_string_list_destroy(warningList);
+ EXPECT_NE(errorList, nullptr);
+ proj_string_list_destroy(errorList);
+ }
+ {
+ PROJ_STRING_LIST warningList = nullptr;
+ PROJ_STRING_LIST errorList = nullptr;
+ auto obj = proj_obj_create_from_wkt(
+ m_ctxt,
+ GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
+ .c_str(),
+ nullptr, &warningList, &errorList);
+ ObjectKeeper keeper(obj);
+ EXPECT_NE(obj, nullptr);
+ EXPECT_EQ(warningList, nullptr);
+ EXPECT_EQ(errorList, nullptr);
+ }
+ // Warnings: missing projection parameters
+ {
+ PROJ_STRING_LIST warningList = nullptr;
+ PROJ_STRING_LIST errorList = nullptr;
+ auto obj = proj_obj_create_from_wkt(
+ m_ctxt, "PROJCS[\"test\",\n"
+ " GEOGCS[\"WGS 84\",\n"
+ " DATUM[\"WGS_1984\",\n"
+ " SPHEROID[\"WGS 84\",6378137,298.257223563]],\n"
+ " PRIMEM[\"Greenwich\",0],\n"
+ " UNIT[\"degree\",0.0174532925199433]],\n"
+ " PROJECTION[\"Transverse_Mercator\"],\n"
+ " PARAMETER[\"latitude_of_origin\",31],\n"
+ " UNIT[\"metre\",1]]",
+ nullptr, &warningList, &errorList);
+ ObjectKeeper keeper(obj);
+ EXPECT_NE(obj, nullptr);
+ EXPECT_NE(warningList, nullptr);
+ proj_string_list_destroy(warningList);
+ EXPECT_EQ(errorList, nullptr);
+ proj_string_list_destroy(errorList);
+ }
+ {
+ auto obj = proj_obj_create_from_wkt(
+ m_ctxt, "PROJCS[\"test\",\n"
+ " GEOGCS[\"WGS 84\",\n"
+ " DATUM[\"WGS_1984\",\n"
+ " SPHEROID[\"WGS 84\",6378137,298.257223563]],\n"
+ " PRIMEM[\"Greenwich\",0],\n"
+ " UNIT[\"degree\",0.0174532925199433]],\n"
+ " PROJECTION[\"Transverse_Mercator\"],\n"
+ " PARAMETER[\"latitude_of_origin\",31],\n"
+ " UNIT[\"metre\",1]]",
+ nullptr, nullptr, nullptr);
+ ObjectKeeper keeper(obj);
+ EXPECT_NE(obj, nullptr);
+ }
}
// ---------------------------------------------------------------------------
@@ -195,7 +309,7 @@ TEST_F(CApi, proj_obj_as_wkt) {
m_ctxt,
GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
@@ -298,7 +412,7 @@ TEST_F(CApi, proj_obj_as_wkt_check_db_use) {
m_ctxt, "GEOGCS[\"AGD66\",DATUM[\"Australian_Geodetic_Datum_1966\","
"SPHEROID[\"Australian National Spheroid\",6378160,298.25]],"
"PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]]",
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
@@ -316,7 +430,7 @@ TEST_F(CApi, proj_obj_as_wkt_incompatible_WKT1) {
auto obj = proj_obj_create_from_wkt(
m_ctxt,
createBoundCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
@@ -331,7 +445,7 @@ TEST_F(CApi, proj_obj_as_proj_string) {
m_ctxt,
GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
@@ -356,7 +470,7 @@ TEST_F(CApi, proj_obj_as_proj_string_incompatible_WKT1) {
auto obj = proj_obj_create_from_wkt(
m_ctxt,
createBoundCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
@@ -449,7 +563,7 @@ TEST_F(CApi, proj_obj_crs_create_bound_crs_to_WGS84_on_invalid_type) {
->derivingConversion()
->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
@@ -464,7 +578,7 @@ TEST_F(CApi, proj_obj_get_name) {
m_ctxt,
GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
auto name = proj_obj_get_name(obj);
@@ -480,7 +594,7 @@ TEST_F(CApi, proj_obj_get_id_auth_name) {
m_ctxt,
GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
auto auth = proj_obj_get_id_auth_name(obj, 0);
@@ -498,7 +612,7 @@ TEST_F(CApi, proj_obj_get_id_code) {
m_ctxt,
GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
auto code = proj_obj_get_id_code(obj, 0);
@@ -517,7 +631,7 @@ TEST_F(CApi, proj_obj_get_type) {
m_ctxt,
GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
EXPECT_EQ(proj_obj_get_type(obj), PJ_OBJ_TYPE_GEOGRAPHIC_2D_CRS);
@@ -527,7 +641,7 @@ TEST_F(CApi, proj_obj_get_type) {
m_ctxt,
GeographicCRS::EPSG_4979->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
EXPECT_EQ(proj_obj_get_type(obj), PJ_OBJ_TYPE_GEOGRAPHIC_3D_CRS);
@@ -537,7 +651,7 @@ TEST_F(CApi, proj_obj_get_type) {
m_ctxt,
GeographicCRS::EPSG_4978->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
EXPECT_EQ(proj_obj_get_type(obj), PJ_OBJ_TYPE_GEOCENTRIC_CRS);
@@ -547,7 +661,7 @@ TEST_F(CApi, proj_obj_get_type) {
m_ctxt, GeographicCRS::EPSG_4326->datum()
->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
EXPECT_EQ(proj_obj_get_type(obj), PJ_OBJ_TYPE_GEODETIC_REFERENCE_FRAME);
@@ -557,7 +671,7 @@ TEST_F(CApi, proj_obj_get_type) {
m_ctxt, GeographicCRS::EPSG_4326->ellipsoid()
->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
EXPECT_EQ(proj_obj_get_type(obj), PJ_OBJ_TYPE_ELLIPSOID);
@@ -567,7 +681,7 @@ TEST_F(CApi, proj_obj_get_type) {
m_ctxt, createProjectedCRS()
->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
EXPECT_EQ(proj_obj_get_type(obj), PJ_OBJ_TYPE_PROJECTED_CRS);
@@ -577,7 +691,7 @@ TEST_F(CApi, proj_obj_get_type) {
m_ctxt, createVerticalCRS()
->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
EXPECT_EQ(proj_obj_get_type(obj), PJ_OBJ_TYPE_VERTICAL_CRS);
@@ -588,7 +702,7 @@ TEST_F(CApi, proj_obj_get_type) {
->datum()
->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
EXPECT_EQ(proj_obj_get_type(obj), PJ_OBJ_TYPE_VERTICAL_REFERENCE_FRAME);
@@ -599,7 +713,7 @@ TEST_F(CApi, proj_obj_get_type) {
->derivingConversion()
->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
EXPECT_EQ(proj_obj_get_type(obj), PJ_OBJ_TYPE_CONVERSION);
@@ -608,7 +722,7 @@ TEST_F(CApi, proj_obj_get_type) {
auto obj = proj_obj_create_from_wkt(
m_ctxt,
createBoundCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
EXPECT_EQ(proj_obj_get_type(obj), PJ_OBJ_TYPE_BOUND_CRS);
@@ -619,14 +733,14 @@ TEST_F(CApi, proj_obj_get_type) {
->transformation()
->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
EXPECT_EQ(proj_obj_get_type(obj), PJ_OBJ_TYPE_TRANSFORMATION);
}
{
auto obj = proj_obj_create_from_wkt(m_ctxt, "AUTHORITY[\"EPSG\", 4326]",
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_EQ(obj, nullptr);
}
@@ -703,7 +817,7 @@ TEST_F(CApi, proj_crs) {
->exportToWKT(
WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL).get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ASSERT_NE(crs, nullptr);
ObjectKeeper keeper(crs);
EXPECT_TRUE(proj_obj_is_crs(crs));
@@ -772,7 +886,7 @@ TEST_F(CApi, proj_obj_get_prime_meridian) {
->exportToWKT(
WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL).get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ASSERT_NE(crs, nullptr);
ObjectKeeper keeper(crs);
@@ -811,7 +925,7 @@ TEST_F(CApi, proj_crs_compound) {
auto crs = proj_obj_create_from_wkt(
m_ctxt,
createCompoundCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ASSERT_NE(crs, nullptr);
ObjectKeeper keeper(crs);
EXPECT_EQ(proj_obj_get_type(crs), PJ_OBJ_TYPE_COMPOUND_CRS);
@@ -837,7 +951,7 @@ TEST_F(CApi, proj_obj_get_source_target_crs_bound_crs) {
auto crs = proj_obj_create_from_wkt(
m_ctxt,
createBoundCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ASSERT_NE(crs, nullptr);
ObjectKeeper keeper(crs);
@@ -860,7 +974,7 @@ TEST_F(CApi, proj_obj_get_source_target_crs_transformation) {
->transformation()
->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ASSERT_NE(obj, nullptr);
ObjectKeeper keeper(obj);
@@ -881,7 +995,7 @@ TEST_F(CApi, proj_obj_get_source_crs_of_projected_crs) {
auto crs = proj_obj_create_from_wkt(
m_ctxt,
createProjectedCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ASSERT_NE(crs, nullptr);
ObjectKeeper keeper(crs);
@@ -911,7 +1025,8 @@ TEST_F(CApi, proj_obj_get_source_target_crs_conversion_without_crs) {
TEST_F(CApi, proj_obj_get_source_target_crs_invalid_object) {
auto obj = proj_obj_create_from_wkt(
- m_ctxt, "ELLIPSOID[\"WGS 84\",6378137,298.257223563]", nullptr);
+ m_ctxt, "ELLIPSOID[\"WGS 84\",6378137,298.257223563]", nullptr, nullptr,
+ nullptr);
ASSERT_NE(obj, nullptr);
ObjectKeeper keeper(obj);
@@ -1089,7 +1204,7 @@ TEST_F(CApi, transformation_from_boundCRS) {
auto crs = proj_obj_create_from_wkt(
m_ctxt,
createBoundCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ASSERT_NE(crs, nullptr);
ObjectKeeper keeper(crs);
@@ -1465,7 +1580,7 @@ TEST_F(CApi, proj_obj_identify) {
m_ctxt,
GeographicCRS::EPSG_4807->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
{
@@ -1486,7 +1601,7 @@ TEST_F(CApi, proj_obj_identify) {
m_ctxt,
Ellipsoid::GRS1980->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeperEllps(objEllps);
auto res =
proj_obj_identify(m_ctxt, objEllps, nullptr, nullptr, nullptr);
@@ -2245,7 +2360,7 @@ TEST_F(CApi, proj_obj_crs_alter_geodetic_crs) {
auto projCRS = proj_obj_create_from_wkt(
m_ctxt,
createProjectedCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(projCRS);
ASSERT_NE(projCRS, nullptr);
@@ -2306,7 +2421,7 @@ TEST_F(CApi, proj_obj_crs_alter_cs_angular_unit) {
m_ctxt,
GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
.c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(crs);
ASSERT_NE(crs, nullptr);
@@ -2363,7 +2478,7 @@ TEST_F(CApi, proj_obj_crs_alter_cs_linear_unit) {
auto crs = proj_obj_create_from_wkt(
m_ctxt,
createProjectedCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(crs);
ASSERT_NE(crs, nullptr);
@@ -2420,7 +2535,7 @@ TEST_F(CApi, proj_obj_crs_alter_parameters_linear_unit) {
auto crs = proj_obj_create_from_wkt(
m_ctxt,
createProjectedCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
- nullptr);
+ nullptr, nullptr, nullptr);
ObjectKeeper keeper(crs);
ASSERT_NE(crs, nullptr);
diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp
index a385fe87..8272cfb4 100644
--- a/test/unit/test_io.cpp
+++ b/test/unit/test_io.cpp
@@ -446,7 +446,7 @@ TEST(wkt_parse, wkt1_EPSG_4807_grad_mess) {
" PRIMEM[\"Paris\",2.33722917,\n"
" AUTHORITY[\"EPSG\",\"8903\"]],\n"
" UNIT[\"grad\",0.015707963267949,\n"
- " AUTHORITY[\"EPSG\",9105]],\n"
+ " AUTHORITY[\"EPSG\",\"9105\"]],\n"
" AXIS[\"latitude\",NORTH],\n"
" AXIS[\"longitude\",EAST],\n"
" AUTHORITY[\"EPSG\",\"4807\"]]");
@@ -868,7 +868,7 @@ TEST(wkt_parse, wkt1_geocentric) {
" PRIMEM[\"Greenwich\",0,\n"
" AUTHORITY[\"EPSG\",\"8901\"]],\n"
" UNIT[\"metre\",1,\n"
- " AUTHORITY[\"EPSG\",9001]],\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
" AXIS[\"Geocentric X\",OTHER],\n"
" AXIS[\"Geocentric Y\",OTHER],\n"
" AXIS[\"Geocentric Z\",NORTH],\n"
@@ -890,7 +890,7 @@ TEST(wkt_parse, wkt1_geocentric_with_z_OTHER) {
" PRIMEM[\"Greenwich\",0,\n"
" AUTHORITY[\"EPSG\",\"8901\"]],\n"
" UNIT[\"metre\",1,\n"
- " AUTHORITY[\"EPSG\",9001]],\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
" AXIS[\"Geocentric X\",OTHER],\n"
" AXIS[\"Geocentric Y\",OTHER],\n"
" AXIS[\"Geocentric Z\",OTHER],\n"
@@ -1004,7 +1004,7 @@ TEST(wkt_parse, wkt1_projected) {
" PRIMEM[\"Greenwich\",0,\n"
" AUTHORITY[\"EPSG\",\"8901\"]],\n"
" UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",9122]],\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
" AXIS[\"latitude\",NORTH],\n"
" AXIS[\"longitude\",EAST],\n"
" AUTHORITY[\"EPSG\",\"4326\"]],\n"
@@ -1015,7 +1015,7 @@ TEST(wkt_parse, wkt1_projected) {
" PARAMETER[\"false_easting\",500000],\n"
" PARAMETER[\"false_northing\",0],\n"
" UNIT[\"metre\",1,\n"
- " AUTHORITY[\"EPSG\",9001]],\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
" AXIS[\"(E)\",EAST],\n"
" AXIS[\"(N)\",NORTH],\n"
" AUTHORITY[\"EPSG\",\"32631\"]]";
@@ -1037,7 +1037,7 @@ TEST(wkt_parse, wkt1_projected_no_axis) {
" PRIMEM[\"Greenwich\",0,\n"
" AUTHORITY[\"EPSG\",\"8901\"]],\n"
" UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",9122]],\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
" AXIS[\"latitude\",NORTH],\n"
" AXIS[\"longitude\",EAST],\n"
" AUTHORITY[\"EPSG\",\"4326\"]],\n"
@@ -1048,7 +1048,7 @@ TEST(wkt_parse, wkt1_projected_no_axis) {
" PARAMETER[\"false_easting\",500000],\n"
" PARAMETER[\"false_northing\",0],\n"
" UNIT[\"metre\",1,\n"
- " AUTHORITY[\"EPSG\",9001]],\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
" AUTHORITY[\"EPSG\",\"32631\"]]";
auto obj = WKTParser().createFromWKT(wkt);
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
@@ -1753,7 +1753,7 @@ TEST(wkt_parse, vertcrs_WKT1_GDAL) {
" VERT_DATUM[\"Ordnance Datum Newlyn\",2005,\n"
" AUTHORITY[\"EPSG\",\"5101\"]],\n"
" UNIT[\"metre\",1,\n"
- " AUTHORITY[\"EPSG\",9001]],\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
" AXIS[\"gravity-related height\",UP],\n"
" AUTHORITY[\"EPSG\",\"5701\"]]";
@@ -1922,7 +1922,7 @@ TEST(wkt_parse, COMPD_CS) {
" PRIMEM[\"Greenwich\",0,\n"
" AUTHORITY[\"EPSG\",\"8901\"]],\n"
" UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",9122]],\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
" AXIS[\"Latitude\",NORTH],\n"
" AXIS[\"Longitude\",EAST],\n"
" AUTHORITY[\"EPSG\",\"4326\"]],\n"
@@ -1933,7 +1933,7 @@ TEST(wkt_parse, COMPD_CS) {
" PARAMETER[\"false_easting\",500000],\n"
" PARAMETER[\"false_northing\",0],\n"
" UNIT[\"metre\",1,\n"
- " AUTHORITY[\"EPSG\",9001]],\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
" AXIS[\"Easting\",EAST],\n"
" AXIS[\"Northing\",NORTH],\n"
" AUTHORITY[\"EPSG\",\"32631\"]],\n"
@@ -1941,7 +1941,7 @@ TEST(wkt_parse, COMPD_CS) {
" VERT_DATUM[\"Ordnance Datum Newlyn\",2005,\n"
" AUTHORITY[\"EPSG\",\"5101\"]],\n"
" UNIT[\"metre\",1,\n"
- " AUTHORITY[\"EPSG\",9001]],\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
" AXIS[\"Gravity-related height\",UP],\n"
" AUTHORITY[\"EPSG\",\"5701\"]],\n"
" AUTHORITY[\"codespace\",\"code\"]]");
@@ -2213,7 +2213,7 @@ TEST(wkt_parse, projcs_TOWGS84_7terms) {
" PRIMEM[\"Greenwich\",0,\n"
" AUTHORITY[\"EPSG\",\"8901\"]],\n"
" UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",9122]],\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
" AXIS[\"Latitude\",NORTH],\n"
" AXIS[\"Longitude\",EAST]],\n"
" PROJECTION[\"Transverse_Mercator\"],\n"
@@ -2223,7 +2223,7 @@ TEST(wkt_parse, projcs_TOWGS84_7terms) {
" PARAMETER[\"false_easting\",500000],\n"
" PARAMETER[\"false_northing\",0],\n"
" UNIT[\"metre\",1,\n"
- " AUTHORITY[\"EPSG\",9001]],\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
" AXIS[\"Easting\",EAST],\n"
" AXIS[\"Northing\",NORTH]]";
@@ -4607,7 +4607,7 @@ TEST(wkt_parse, invalid_PROJCS) {
" AUTHORITY[\"EPSG\",\"6326\"]],\n"
" PRIMEM[\"x\",0],\n"
" UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",9122]],\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
" AXIS[\"latitude\",NORTH],\n"
" AXIS[\"longitude\",EAST],\n"
" AUTHORITY[\"EPSG\",\"4326\"]]\n");
@@ -4627,17 +4627,17 @@ TEST(wkt_parse, invalid_PROJCS) {
ParsingException);
// not enough children in PARAMETER
- EXPECT_THROW(
- WKTParser().createFromWKT(
- startWKT +
- ",PROJECTION[\"x\"],PARAMETER[\"z\",\"foo\"],UNIT[\"metre\",1]]"),
- ParsingException);
+ EXPECT_THROW(WKTParser().createFromWKT(
+ startWKT +
+ ",PROJECTION[\"x\"],PARAMETER[\"z\"],UNIT[\"metre\",1]]"),
+ ParsingException);
EXPECT_NO_THROW(WKTParser().createFromWKT(
- startWKT + ",PROJECTION[\"x\"],UNIT[\"metre\",1]]"));
+ startWKT + ",PROJECTION[\"x\"],PARAMETER[\"z\",1],UNIT[\"metre\",1]]"));
// missing UNIT
- EXPECT_THROW(WKTParser().createFromWKT(startWKT + ",PROJECTION[\"x\"]]"),
+ EXPECT_THROW(WKTParser().createFromWKT(
+ startWKT + ",PROJECTION[\"x\"],PARAMETER[\"z\",1]]"),
ParsingException);
}
diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp
index 905eecdb..636db7a7 100644
--- a/test/unit/test_operation.cpp
+++ b/test/unit/test_operation.cpp
@@ -3310,7 +3310,7 @@ TEST(operation, webmerc_import_from_broken_esri_WGS_84_Pseudo_Mercator) {
"PARAMETER[\"false_northing\",0],UNIT[\"Meter\",1],"
"PARAMETER[\"standard_parallel_1\",0.0]]";
- auto obj = WKTParser().createFromWKT(wkt1);
+ auto obj = WKTParser().setStrict(false).createFromWKT(wkt1);
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);
@@ -3620,7 +3620,7 @@ TEST(operation, wkt1_import_polar_stereographic_variantA) {
" PARAMETER[\"central_meridian\",2],\n"
" PARAMETER[\"scale_factor\",3],\n"
" PARAMETER[\"false_easting\",4],\n"
- " PARAMETER[\"false_northing\",5]"
+ " PARAMETER[\"false_northing\",5],\n"
" UNIT[\"metre\",1]]";
auto obj = WKTParser().createFromWKT(wkt);
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
@@ -3649,7 +3649,7 @@ TEST(operation, wkt1_import_polar_stereographic_variantB) {
" PARAMETER[\"central_meridian\",2],\n"
" PARAMETER[\"scale_factor\",1],\n"
" PARAMETER[\"false_easting\",4],\n"
- " PARAMETER[\"false_northing\",5]"
+ " PARAMETER[\"false_northing\",5],\n"
" UNIT[\"metre\",1]]";
auto obj = WKTParser().createFromWKT(wkt);
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
@@ -3678,7 +3678,7 @@ TEST(operation, wkt1_import_polar_stereographic_ambiguous) {
" PARAMETER[\"central_meridian\",2],\n"
" PARAMETER[\"scale_factor\",3],\n"
" PARAMETER[\"false_easting\",4],\n"
- " PARAMETER[\"false_northing\",5]"
+ " PARAMETER[\"false_northing\",5],\n"
" UNIT[\"metre\",1]]";
auto obj = WKTParser().createFromWKT(wkt);
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
@@ -6827,9 +6827,9 @@ TEST(operation, conversion_missing_parameter) {
" PARAMETER[\"false_easting\",500000],"
" UNIT[\"metre\",1,"
" AUTHORITY[\"EPSG\",\"9001\"]],"
- " AUTHORITY[\"EPSG\",\"2038\"],"
" AXIS[\"Easting\",EAST],"
- " AXIS[\"Northing\",NORTH]]";
+ " AXIS[\"Northing\",NORTH],"
+ " AUTHORITY[\"EPSG\",\"2038\"]]";
auto obj1 = WKTParser().createFromWKT(wkt1);
auto crs1 = nn_dynamic_pointer_cast<ProjectedCRS>(obj1);
ASSERT_TRUE(crs1 != nullptr);
@@ -6854,9 +6854,9 @@ TEST(operation, conversion_missing_parameter) {
" PARAMETER[\"false_northing\",0],"
" UNIT[\"metre\",1,"
" AUTHORITY[\"EPSG\",\"9001\"]],"
- " AUTHORITY[\"EPSG\",\"2038\"],"
" AXIS[\"Easting\",EAST],"
- " AXIS[\"Northing\",NORTH]]";
+ " AXIS[\"Northing\",NORTH],"
+ " AUTHORITY[\"EPSG\",\"2038\"]]";
auto obj2 = WKTParser().createFromWKT(wkt2);
auto crs2 = nn_dynamic_pointer_cast<ProjectedCRS>(obj2);
ASSERT_TRUE(crs2 != nullptr);
@@ -6881,9 +6881,9 @@ TEST(operation, conversion_missing_parameter) {
" PARAMETER[\"false_northing\",0],"
" UNIT[\"metre\",1,"
" AUTHORITY[\"EPSG\",\"9001\"]],"
- " AUTHORITY[\"EPSG\",\"2038\"],"
" AXIS[\"Easting\",EAST],"
- " AXIS[\"Northing\",NORTH]]";
+ " AXIS[\"Northing\",NORTH],"
+ " AUTHORITY[\"EPSG\",\"2038\"]]";
auto obj3 = WKTParser().createFromWKT(wkt3);
auto crs3 = nn_dynamic_pointer_cast<ProjectedCRS>(obj3);
ASSERT_TRUE(crs3 != nullptr);
@@ -6909,9 +6909,9 @@ TEST(operation, conversion_missing_parameter) {
" PARAMETER[\"UNKNOWN\",13],"
" UNIT[\"metre\",1,"
" AUTHORITY[\"EPSG\",\"9001\"]],"
- " AUTHORITY[\"EPSG\",\"2038\"],"
" AXIS[\"Easting\",EAST],"
- " AXIS[\"Northing\",NORTH]]";
+ " AXIS[\"Northing\",NORTH],"
+ " AUTHORITY[\"EPSG\",\"2038\"]]";
auto obj4 = WKTParser().createFromWKT(wkt4);
auto crs4 = nn_dynamic_pointer_cast<ProjectedCRS>(obj4);
ASSERT_TRUE(crs4 != nullptr);
@@ -6936,9 +6936,9 @@ TEST(operation, conversion_missing_parameter) {
" PARAMETER[\"false_northing\",-99999],"
" UNIT[\"metre\",1,"
" AUTHORITY[\"EPSG\",\"9001\"]],"
- " AUTHORITY[\"EPSG\",\"2038\"],"
" AXIS[\"Easting\",EAST],"
- " AXIS[\"Northing\",NORTH]]";
+ " AXIS[\"Northing\",NORTH],"
+ " AUTHORITY[\"EPSG\",\"2038\"]]";
auto obj5 = WKTParser().createFromWKT(wkt5);
auto crs5 = nn_dynamic_pointer_cast<ProjectedCRS>(obj5);
ASSERT_TRUE(crs5 != nullptr);
diff --git a/travis/csa/install.sh b/travis/csa/install.sh
index 4df403e0..301aead9 100755
--- a/travis/csa/install.sh
+++ b/travis/csa/install.sh
@@ -8,4 +8,4 @@ set -e
CXXFLAGS="-std=c++11" ./clang+llvm-6.0.0-x86_64-linux-gnu-ubuntu-14.04/bin/scan-build -o scanbuildoutput -plist -v ./configure
./clang+llvm-6.0.0-x86_64-linux-gnu-ubuntu-14.04/bin/scan-build -o scanbuildoutput -plist -v make -j3
-if grep -r "\.c" scanbuildoutput | grep "<string>" | grep -v "<key>"; then echo "error" && /bin/false; else echo "ok"; fi
+if grep -r "\.c" scanbuildoutput | grep "<string>" | grep -v -e "<key>" -e _generated_parser; then echo "error" && /bin/false; else echo "ok"; fi