From 56075006131263e0859808d263d6d22cd4594fb9 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 29 Aug 2017 10:25:47 +0200 Subject: PJ_horner.c: fix memory leaks. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3204. Credit to OSS Fuzz --- src/PJ_horner.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/PJ_horner.c b/src/PJ_horner.c index 56980f72..c6560d3a 100644 --- a/src/PJ_horner.c +++ b/src/PJ_horner.c @@ -128,6 +128,8 @@ static void horner_free (HORNER *h) { horner_dealloc (h->fwd_u); horner_dealloc (h->fwd_c); horner_dealloc (h->inv_c); + horner_dealloc (h->fwd_origin); + horner_dealloc (h->inv_origin); horner_dealloc (h); } @@ -406,8 +408,10 @@ static int parse_coefs (PJ *P, double *coefs, char *param, int ncoefs) { } sprintf (buf, "t%s", param); - if (0==pj_param (P->ctx, P->params, buf).i) + if (0==pj_param (P->ctx, P->params, buf).i) { + pj_dealloc (buf); return 0; + } sprintf (buf, "s%s", param); init = pj_param(P->ctx, P->params, buf).s; pj_dealloc (buf); -- cgit v1.2.3 From d5c5a70ef763375c9c57cf701c73532a9cdaf802 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 29 Aug 2017 10:26:15 +0200 Subject: Add myself to AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index f114a2ea..534ddd22 100644 --- a/AUTHORS +++ b/AUTHORS @@ -16,3 +16,4 @@ Karsten Engsager Knud Poder Kristian Evers Thomas Knudsen +Even Rouault -- cgit v1.2.3 From 2a13208980a42b645e72486109a9ae02a92238a3 Mon Sep 17 00:00:00 2001 From: Charles Karney Date: Tue, 29 Aug 2017 15:58:00 -0400 Subject: Release candidate for geodesic library version 1.49. Only substantial changes are (1) testing the HAVE_C99_MATH flag and acting accordingly and (2) adding a couple of tests. --- man/man3/geodesic.3 | 4 ++-- src/geodesic.c | 40 +++++++++++++++++++++++++++++++++++++--- src/geodesic.h | 26 +++++++++++++------------- src/geodtest.c | 42 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 89 insertions(+), 23 deletions(-) diff --git a/man/man3/geodesic.3 b/man/man3/geodesic.3 index 310fc3d5..938eed68 100644 --- a/man/man3/geodesic.3 +++ b/man/man3/geodesic.3 @@ -53,7 +53,7 @@ measure angles (latitudes, longitudes, and azimuths) in degrees, unlike the rest of the \fBproj\fR library, which uses radians. The documentation for this library is included in geodesic.h. A formatted version of the documentation is available at -https://geographiclib.sourceforge.io/1.48/C +https://geographiclib.sourceforge.io/1.49/C .SH EXAMPLE The following program reads in lines with the coordinates for two points in decimal degrees (\fIlat1\fR, \fIlon1\fR, \fIlat2\fR, \fIlon2\fR) and @@ -87,7 +87,7 @@ libproj.a \- library of projections and support procedures .SH SEE ALSO Full online documentation for \fBgeodesic(3)\fR, .br -https://geographiclib.sourceforge.io/1.48/C +https://geographiclib.sourceforge.io/1.49/C .PP .B geod(1) .PP diff --git a/src/geodesic.c b/src/geodesic.c index aeb82c71..84951d7f 100644 --- a/src/geodesic.c +++ b/src/geodesic.c @@ -26,6 +26,10 @@ #include "geodesic.h" #include +#if !defined(HAVE_C99_MATH) +#define HAVE_C99_MATH 0 +#endif + #define GEOGRAPHICLIB_GEODESIC_ORDER 6 #define nA1 GEOGRAPHICLIB_GEODESIC_ORDER #define nC1 GEOGRAPHICLIB_GEODESIC_ORDER @@ -105,6 +109,12 @@ enum captype { }; static real sq(real x) { return x * x; } +#if HAVE_C99_MATH +#define atanhx atanh +#define copysignx copysign +#define hypotx hypot +#define cbrtx cbrt +#else static real log1px(real x) { volatile real y = 1 + x, @@ -133,6 +143,7 @@ static real cbrtx(real x) { real y = pow(fabs(x), 1/(real)(3)); /* Return the real cube root */ return x < 0 ? -y : y; } +#endif static real sumx(real u, real v, real* t) { volatile real s = u + v; @@ -170,8 +181,13 @@ static void norm2(real* sinx, real* cosx) { } static real AngNormalize(real x) { +#if HAVE_C99_MATH + x = remainder(x, (real)(360)); + return x != -180 ? x : 180; +#else x = fmod(x, (real)(360)); return x <= -180 ? x + 360 : (x <= 180 ? x : x - 360); +#endif } static real LatFix(real x) @@ -202,9 +218,15 @@ static void sincosdx(real x, real* sinx, real* cosx) { /* In order to minimize round-off errors, this function exactly reduces * the argument to the range [-45, 45] before converting it to radians. */ real r, s, c; int q; +#if HAVE_C99_MATH && !defined(__GNUC__) + /* Disable for gcc because of bug in glibc version < 2.22, see + * https://sourceware.org/bugzilla/show_bug.cgi?id=17569 */ + r = remquo(x, (real)(90), &q); +#else r = fmod(x, (real)(360)); q = (int)(floor(r / 90 + (real)(0.5))); r -= 90 * q; +#endif /* now abs(r) <= 45 */ r *= degree; /* Possibly could call the gnu extension sincos */ @@ -538,7 +560,9 @@ real geod_genposition(const struct geod_geodesicline* l, salp2 = l->salp0; calp2 = l->calp0 * csig2; /* No need to normalize */ if (outmask & GEOD_DISTANCE) - s12 = flags & GEOD_ARCMODE ? l->b * ((1 + l->A1m1) * sig12 + AB1) : s12_a12; + s12 = flags & GEOD_ARCMODE ? + l->b * ((1 + l->A1m1) * sig12 + AB1) : + s12_a12; if (outmask & GEOD_LONGITUDE) { real E = copysignx(1, l->salp0); /* east or west going? */ @@ -576,7 +600,8 @@ real geod_genposition(const struct geod_geodesicline* l, m12 = l->b * ((dn2 * (l->csig1 * ssig2) - l->dn1 * (l->ssig1 * csig2)) - l->csig1 * csig2 * J12); if (outmask & GEOD_GEODESICSCALE) { - real t = l->k2 * (ssig2 - l->ssig1) * (ssig2 + l->ssig1) / (l->dn1 + dn2); + real t = l->k2 * (ssig2 - l->ssig1) * (ssig2 + l->ssig1) / + (l->dn1 + dn2); M12 = csig12 + (t * ssig2 - csig2 * J12) * l->ssig1 / l->dn1; M21 = csig12 - (t * l->ssig1 - l->csig1 * J12) * ssig2 / dn2; } @@ -639,7 +664,9 @@ static void geod_setarc(struct geod_geodesicline* l, real a13) { void geod_gensetdistance(struct geod_geodesicline* l, unsigned flags, real s13_a13) { - flags & GEOD_ARCMODE ? geod_setarc(l, s13_a13) : geod_setdistance(l, s13_a13); + flags & GEOD_ARCMODE ? + geod_setarc(l, s13_a13) : + geod_setdistance(l, s13_a13); } void geod_position(const struct geod_geodesicline* l, real s12, @@ -1758,10 +1785,17 @@ int transit(real lon1, real lon2) { } int transitdirect(real lon1, real lon2) { +#if HAVE_C99_MATH + lon1 = remainder(lon1, (real)(720)); + lon2 = remainder(lon2, (real)(720)); + return ( (lon2 >= 0 && lon2 < 360 ? 0 : 1) - + (lon1 >= 0 && lon1 < 360 ? 0 : 1) ); +#else lon1 = fmod(lon1, (real)(720)); lon2 = fmod(lon2, (real)(720)); return ( ((lon2 >= 0 && lon2 < 360) || lon2 < -360 ? 0 : 1) - ((lon1 >= 0 && lon1 < 360) || lon1 < -360 ? 0 : 1) ); +#endif } void accini(real s[]) { diff --git a/src/geodesic.h b/src/geodesic.h index f3cb3009..ab18a01f 100644 --- a/src/geodesic.h +++ b/src/geodesic.h @@ -112,7 +112,7 @@ * https://geographiclib.sourceforge.io/ * * This library was distributed with - * GeographicLib 1.48. + * GeographicLib 1.49. **********************************************************************/ #if !defined(GEODESIC_H) @@ -127,12 +127,12 @@ * The minor version of the geodesic library. (This tracks the version of * GeographicLib.) **********************************************************************/ -#define GEODESIC_VERSION_MINOR 48 +#define GEODESIC_VERSION_MINOR 49 /** * The patch level of the geodesic library. (This tracks the version of * GeographicLib.) **********************************************************************/ -#define GEODESIC_VERSION_PATCH 1 +#define GEODESIC_VERSION_PATCH 0 /** * Pack the version components into a single integer. Users should not rely on @@ -881,16 +881,16 @@ extern "C" { * mask values for the \e caps argument to geod_lineinit(). **********************************************************************/ enum geod_mask { - GEOD_NONE = 0U, /**< Calculate nothing */ - GEOD_LATITUDE = 1U<<7 | 0U, /**< Calculate latitude */ - GEOD_LONGITUDE = 1U<<8 | 1U<<3, /**< Calculate longitude */ - GEOD_AZIMUTH = 1U<<9 | 0U, /**< Calculate azimuth */ - GEOD_DISTANCE = 1U<<10 | 1U<<0, /**< Calculate distance */ - GEOD_DISTANCE_IN = 1U<<11 | 1U<<0 | 1U<<1, /**< Allow distance as input */ - GEOD_REDUCEDLENGTH= 1U<<12 | 1U<<0 | 1U<<2, /**< Calculate reduced length */ - GEOD_GEODESICSCALE= 1U<<13 | 1U<<0 | 1U<<2, /**< Calculate geodesic scale */ - GEOD_AREA = 1U<<14 | 1U<<4, /**< Calculate reduced length */ - GEOD_ALL = 0x7F80U| 0x1FU /**< Calculate everything */ + GEOD_NONE = 0U, /**< Calculate nothing */ + GEOD_LATITUDE = 1U<<7 | 0U, /**< Calculate latitude */ + GEOD_LONGITUDE = 1U<<8 | 1U<<3, /**< Calculate longitude */ + GEOD_AZIMUTH = 1U<<9 | 0U, /**< Calculate azimuth */ + GEOD_DISTANCE = 1U<<10 | 1U<<0, /**< Calculate distance */ + GEOD_DISTANCE_IN = 1U<<11 | 1U<<0 | 1U<<1,/**< Allow distance as input */ + GEOD_REDUCEDLENGTH= 1U<<12 | 1U<<0 | 1U<<2,/**< Calculate reduced length */ + GEOD_GEODESICSCALE= 1U<<13 | 1U<<0 | 1U<<2,/**< Calculate geodesic scale */ + GEOD_AREA = 1U<<14 | 1U<<4, /**< Calculate reduced length */ + GEOD_ALL = 0x7F80U| 0x1FU /**< Calculate everything */ }; /** diff --git a/src/geodtest.c b/src/geodtest.c index 5ca741b1..6899436c 100644 --- a/src/geodtest.c +++ b/src/geodtest.c @@ -16,7 +16,7 @@ #include #if defined(_MSC_VER) -// Squelch warnings about assignment within conditional expression +/* Squelch warnings about assignment within conditional expression */ # pragma warning (disable: 4706) #endif @@ -618,8 +618,9 @@ static int GeodSolve73() { return result; } -static void planimeter(const struct geod_geodesic* g, double points[][2], int N, - double* perimeter, double* area) { +static void planimeter(const struct geod_geodesic* g, + double points[][2], int N, + double* perimeter, double* area) { struct geod_polygon p; int i; geod_polygon_init(&p, 0); @@ -628,8 +629,9 @@ static void planimeter(const struct geod_geodesic* g, double points[][2], int N, geod_polygon_compute(g, &p, 0, 1, area, perimeter); } -static void polylength(const struct geod_geodesic* g, double points[][2], int N, - double* perimeter) { +static void polylength(const struct geod_geodesic* g, + double points[][2], int N, + double* perimeter) { struct geod_polygon p; int i; geod_polygon_init(&p, 1); @@ -658,6 +660,34 @@ static int GeodSolve74() { return result; } +static int GeodSolve76() { + /* The distance from Wellington and Salamanca (a classic failure of + Vincenty) */ + double azi1, azi2, s12; + struct geod_geodesic g; + int result = 0; + geod_init(&g, wgs84_a, wgs84_f); + geod_inverse(&g, -(41+19/60.0), 174+49/60.0, 40+58/60.0, -(5+30/60.0), + &s12, &azi1, &azi2); + result += assertEquals(azi1, 160.39137649664, 0.5e-11); + result += assertEquals(azi2, 19.50042925176, 0.5e-11); + result += assertEquals(s12, 19960543.857179, 0.5e-6); + return result; +} + +static int GeodSolve78() { + /* An example where the NGS calculator fails to converge */ + double azi1, azi2, s12; + struct geod_geodesic g; + int result = 0; + geod_init(&g, wgs84_a, wgs84_f); + geod_inverse(&g, 27.2, 0.0, -27.1, 179.5, &s12, &azi1, &azi2); + result += assertEquals(azi1, 45.82468716758, 0.5e-11); + result += assertEquals(azi2, 134.22776532670, 0.5e-11); + result += assertEquals(s12, 19974354.765767, 0.5e-6); + return result; +} + static int Planimeter0() { /* Check fix for pole-encircling bug found 2011-03-16 */ double pa[4][2] = {{89, 0}, {89, 90}, {89, 180}, {89, 270}}; @@ -786,6 +816,8 @@ int main() { if ((i = GeodSolve71())) {++n; printf("GeodSolve71 fail: %d\n", i);} if ((i = GeodSolve73())) {++n; printf("GeodSolve73 fail: %d\n", i);} if ((i = GeodSolve74())) {++n; printf("GeodSolve74 fail: %d\n", i);} + if ((i = GeodSolve76())) {++n; printf("GeodSolve76 fail: %d\n", i);} + if ((i = GeodSolve78())) {++n; printf("GeodSolve78 fail: %d\n", i);} if ((i = Planimeter0())) {++n; printf("Planimeter0 fail: %d\n", i);} if ((i = Planimeter5())) {++n; printf("Planimeter5 fail: %d\n", i);} if ((i = Planimeter6())) {++n; printf("Planimeter6 fail: %d\n", i);} -- cgit v1.2.3 From 9b664865a2926568440de57f4d3f5a64e0cee6dc Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 30 Aug 2017 10:19:59 +0200 Subject: urm5: fix memory leaks in error code paths of initialization. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3235. Credit to OSS Fuzz --- src/PJ_urm5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PJ_urm5.c b/src/PJ_urm5.c index 9d904fc7..4edb4215 100644 --- a/src/PJ_urm5.c +++ b/src/PJ_urm5.c @@ -47,11 +47,11 @@ PJ *PROJECTION(urm5) { Q->n = pj_param(P->ctx, P->params, "dn").f; if (Q->n <= 0. || Q->n > 1.) { proj_errno_set(P, PJD_ERR_N_OUT_OF_RANGE); - return freeup_new(0); + return freeup_new(P); } } else { proj_errno_set(P, PJD_ERR_N_OUT_OF_RANGE); - return freeup_new(0); + return freeup_new(P); } Q->q3 = pj_param(P->ctx, P->params, "dq").f / 3.; alpha = pj_param(P->ctx, P->params, "ralpha").f; -- cgit v1.2.3 From 03eb6a7804019df8c90014c1fb5dd885bc08b40e Mon Sep 17 00:00:00 2001 From: Charles Karney Date: Wed, 30 Aug 2017 09:54:41 -0400 Subject: Add geodtest to autoconf's 'make check' suite. It's already including in cmake's test suite. --- src/Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Makefile.am b/src/Makefile.am index dbfefe9c..12d11c5f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,9 @@ AM_CFLAGS = @C_WFLAGS@ bin_PROGRAMS = proj nad2bin geod cs2cs EXTRA_PROGRAMS = multistresstest test228 +TESTS = geodtest +check_PROGRAMS = geodtest + AM_CPPFLAGS = -DPROJ_LIB=\"$(pkgdatadir)\" \ -DMUTEX_@MUTEX_SETTING@ @JNI_INCLUDE@ @@ -19,6 +22,7 @@ nad2bin_SOURCES = nad2bin.c geod_SOURCES = geod.c geod_set.c geod_interface.c geod_interface.h multistresstest_SOURCES = multistresstest.c test228_SOURCES = test228.c +geodtest_SOURCES = geodtest.c proj_LDADD = libproj.la cs2cs_LDADD = libproj.la @@ -26,6 +30,7 @@ nad2bin_LDADD = libproj.la geod_LDADD = libproj.la multistresstest_LDADD = libproj.la @THREAD_LIB@ test228_LDADD = libproj.la @THREAD_LIB@ +geodtest_LDADD = libproj.la lib_LTLIBRARIES = libproj.la -- cgit v1.2.3 From f658c3c822e65ec907e44f14c937aef7824d404c Mon Sep 17 00:00:00 2001 From: Charles Karney Date: Wed, 30 Aug 2017 10:11:33 -0400 Subject: Rejig how geodtest is specified in automake to make coverage stats accurate?? --- src/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 12d11c5f..d215e678 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,7 +22,7 @@ nad2bin_SOURCES = nad2bin.c geod_SOURCES = geod.c geod_set.c geod_interface.c geod_interface.h multistresstest_SOURCES = multistresstest.c test228_SOURCES = test228.c -geodtest_SOURCES = geodtest.c +geodtest_SOURCES = geodtest.c geod.c proj_LDADD = libproj.la cs2cs_LDADD = libproj.la @@ -30,7 +30,6 @@ nad2bin_LDADD = libproj.la geod_LDADD = libproj.la multistresstest_LDADD = libproj.la @THREAD_LIB@ test228_LDADD = libproj.la @THREAD_LIB@ -geodtest_LDADD = libproj.la lib_LTLIBRARIES = libproj.la -- cgit v1.2.3 From 195c883b7f76bd5193052f3d5532e73005eadf0c Mon Sep 17 00:00:00 2001 From: Charles Karney Date: Wed, 30 Aug 2017 10:43:48 -0400 Subject: Back out of previous change. Coverage stats are still wrong. geodtest should have included geodesic.c and not geod.c and yet I'm not allowed to use geodesic.c except through the library and then the coverage of geodesic.c seems to be wildly wrong. --- src/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index d215e678..12d11c5f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,7 +22,7 @@ nad2bin_SOURCES = nad2bin.c geod_SOURCES = geod.c geod_set.c geod_interface.c geod_interface.h multistresstest_SOURCES = multistresstest.c test228_SOURCES = test228.c -geodtest_SOURCES = geodtest.c geod.c +geodtest_SOURCES = geodtest.c proj_LDADD = libproj.la cs2cs_LDADD = libproj.la @@ -30,6 +30,7 @@ nad2bin_LDADD = libproj.la geod_LDADD = libproj.la multistresstest_LDADD = libproj.la @THREAD_LIB@ test228_LDADD = libproj.la @THREAD_LIB@ +geodtest_LDADD = libproj.la lib_LTLIBRARIES = libproj.la -- cgit v1.2.3 -- cgit v1.2.3 From efe7db5daf1067d57be1726193a7b59d5ba038af Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sun, 3 Sep 2017 10:21:15 +0200 Subject: PJ_goode: fix memory leak. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3274. Credit to OSS Fuzz --- src/PJ_goode.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/PJ_goode.c b/src/PJ_goode.c index fff12a78..9138cedc 100644 --- a/src/PJ_goode.c +++ b/src/PJ_goode.c @@ -49,9 +49,9 @@ static void *freeup_new (PJ *P) { /* Destructor */ if (0==P->opaque) return pj_dealloc(P); if (P->opaque->sinu) - pj_dealloc(P->opaque->sinu); + pj_free(P->opaque->sinu); if (P->opaque->moll) - pj_dealloc(P->opaque->moll); + pj_free(P->opaque->moll); pj_dealloc (P->opaque); return pj_dealloc(P); @@ -104,7 +104,11 @@ int pj_goode_selftest (void) { }; XY s_fwd_expect[] = { - { 223368.11902663155, 111701.07212763709}, { 223368.11902663155, -111701.07212763709}, {-223368.11902663155, 111701.07212763709}, {-223368.11902663155, -111701.07212763709}, }; + { 223368.11902663155, 111701.07212763709}, + { 223368.11902663155, -111701.07212763709}, + {-223368.11902663155, 111701.07212763709}, + {-223368.11902663155, -111701.07212763709}, + }; XY inv_in[] = { { 200, 100}, @@ -114,7 +118,11 @@ int pj_goode_selftest (void) { }; LP s_inv_expect[] = { - { 0.0017904931100023887, 0.00089524655489191132}, { 0.0017904931100023887, -0.00089524655489191132}, {-0.0017904931100023887, 0.00089524655489191132}, {-0.0017904931100023887, -0.00089524655489191132}, }; + { 0.0017904931100023887, 0.00089524655489191132}, + { 0.0017904931100023887, -0.00089524655489191132}, + {-0.0017904931100023887, 0.00089524655489191132}, + {-0.0017904931100023887, -0.00089524655489191132}, + }; return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, inv_in, 0, s_inv_expect); } -- cgit v1.2.3 From 0d50cc980df7b5b25be8ea29689cdfe08c587650 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 4 Sep 2017 09:51:14 +0200 Subject: PJ_hgridshift.c: fix memleak in initialization if grid loading fail. Same fix as commit e1ad1046873056ab3bfc3262bd343e8c874f395c. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3276. Credit to OSS Fuzz --- src/PJ_hgridshift.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PJ_hgridshift.c b/src/PJ_hgridshift.c index 41c2b629..674b4da8 100644 --- a/src/PJ_hgridshift.c +++ b/src/PJ_hgridshift.c @@ -81,6 +81,8 @@ PJ *PROJECTION(hgridshift) { /* Was gridlist compiled properly? */ if ( pj_ctx_get_errno(P->ctx) ) { proj_log_error(P, "hgridshift: could not find required grid(s)."); + pj_dalloc(P->gridlist); + P->gridlist = NULL; return freeup_msg(P, -38); } -- cgit v1.2.3 From 60970de2d0e47f40c7a30222eba0c1de511ea0a1 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 5 Sep 2017 11:23:02 +0200 Subject: Reformat proj.c before making functional changes. Mixed usage of tabs and spaces replaced with spaces. Code slightly reformatted to present a consistent style from top to bottom. --- src/proj.c | 507 +++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 271 insertions(+), 236 deletions(-) diff --git a/src/proj.c b/src/proj.c index 67d60f21..70ca4033 100644 --- a/src/proj.c +++ b/src/proj.c @@ -21,243 +21,274 @@ extern void gen_cheb(int, projUV(*)(projUV), char *, PJ *, int, char **); +static PJ *Proj; +static projUV (*proj)(projUV, PJ *); - static PJ -*Proj; - static projUV -(*proj)(projUV, PJ *); - static int -reversein = 0, /* != 0 reverse input arguments */ -reverseout = 0, /* != 0 reverse output arguments */ -bin_in = 0, /* != 0 then binary input */ -bin_out = 0, /* != 0 then binary output */ -echoin = 0, /* echo input data to output line */ -tag = '#', /* beginning of line tag character */ -inverse = 0, /* != 0 then inverse projection */ -prescale = 0, /* != 0 apply cartesian scale factor */ -dofactors = 0, /* determine scale factors */ -facs_bad = 0, /* return condition from pj_factors */ -very_verby = 0, /* very verbose mode */ -postscale = 0; - static char -*cheby_str, /* string controlling Chebychev evaluation */ -*oform = (char *)0, /* output format for x-y or decimal degrees */ -*oterr = "*\t*", /* output line for unprojectable input */ -*usage = -"%s\nusage: %s [ -bCeEfiIlormsStTvVwW [args] ] [ +opts[=arg] ] [ files ]\n"; - static struct FACTORS -facs; - static double -(*informat)(const char *, char **), /* input data deformatter function */ -fscale = 0.; /* cartesian scale factor */ - static projUV -int_proj(projUV data) { - if (prescale) { data.u *= fscale; data.v *= fscale; } - data = (*proj)(data, Proj); - if (postscale && data.u != HUGE_VAL) - { data.u *= fscale; data.v *= fscale; } - return(data); +static int + reversein = 0, /* != 0 reverse input arguments */ + reverseout = 0, /* != 0 reverse output arguments */ + bin_in = 0, /* != 0 then binary input */ + bin_out = 0, /* != 0 then binary output */ + echoin = 0, /* echo input data to output line */ + tag = '#', /* beginning of line tag character */ + inverse = 0, /* != 0 then inverse projection */ + prescale = 0, /* != 0 apply cartesian scale factor */ + dofactors = 0, /* determine scale factors */ + facs_bad = 0, /* return condition from pj_factors */ + very_verby = 0, /* very verbose mode */ + postscale = 0; + +static char + *cheby_str, /* string controlling Chebychev evaluation */ + *oform = (char *)0, /* output format for x-y or decimal degrees */ + *oterr = "*\t*", /* output line for unprojectable input */ + *usage = "%s\nusage: %s [ -bCeEfiIlormsStTvVwW [args] ] [ +opts[=arg] ] [ files ]\n"; + +static struct FACTORS facs; + +static double (*informat)(const char *, char **), /* input data deformatter function */ + fscale = 0.; /* cartesian scale factor */ + +static projUV int_proj(projUV data) { + if (prescale) { + data.u *= fscale; + data.v *= fscale; + } + + data = (*proj)(data, Proj); + + if (postscale && data.u != HUGE_VAL) { + data.u *= fscale; + data.v *= fscale; + } + + return data; } - static void /* file processing function */ -process(FILE *fid) { - char line[MAX_LINE+3], *s = 0, pline[40]; - projUV data; - - for (;;) { - ++emess_dat.File_line; - if (bin_in) { /* binary input */ - if (fread(&data, sizeof(projUV), 1, fid) != 1) - break; - } else { /* ascii input */ - if (!(s = fgets(line, MAX_LINE, fid))) - break; - if (!strchr(s, '\n')) { /* overlong line */ - int c; - (void)strcat(s, "\n"); - /* gobble up to newline */ - while ((c = fgetc(fid)) != EOF && c != '\n') ; - } - if (*s == tag) { - if (!bin_out) - (void)fputs(line, stdout); - continue; - } - if (reversein) { - data.v = (*informat)(s, &s); - data.u = (*informat)(s, &s); - } else { - data.u = (*informat)(s, &s); - data.v = (*informat)(s, &s); - } - if (data.v == HUGE_VAL) - data.u = HUGE_VAL; - if (!*s && (s > line)) --s; /* assumed we gobbled \n */ - if (!bin_out && echoin) { - char t; - t = *s; - *s = '\0'; - (void)fputs(line, stdout); - *s = t; - putchar('\t'); - } - } - if (data.u != HUGE_VAL) { - if (prescale) { data.u *= fscale; data.v *= fscale; } - if (dofactors && !inverse) - facs_bad = pj_factors(data, Proj, 0., &facs); - data = (*proj)(data, Proj); - if (dofactors && inverse) - facs_bad = pj_factors(data, Proj, 0., &facs); - if (postscale && data.u != HUGE_VAL) - { data.u *= fscale; data.v *= fscale; } - } - if (bin_out) { /* binary output */ - (void)fwrite(&data, sizeof(projUV), 1, stdout); - continue; - } else if (data.u == HUGE_VAL) /* error output */ - (void)fputs(oterr, stdout); - else if (inverse && !oform) { /*ascii DMS output */ - if (reverseout) { - (void)fputs(rtodms(pline, data.v, 'N', 'S'), stdout); - putchar('\t'); - (void)fputs(rtodms(pline, data.u, 'E', 'W'), stdout); - } else { - (void)fputs(rtodms(pline, data.u, 'E', 'W'), stdout); - putchar('\t'); - (void)fputs(rtodms(pline, data.v, 'N', 'S'), stdout); - } - } else { /* x-y or decimal degree ascii output */ - if (inverse) { - data.v *= RAD_TO_DEG; - data.u *= RAD_TO_DEG; - } - if (reverseout) { - (void)printf(oform,data.v); putchar('\t'); - (void)printf(oform,data.u); - } else { - (void)printf(oform,data.u); putchar('\t'); - (void)printf(oform,data.v); - } - } - if (dofactors) /* print scale factor data */ - { - if (!facs_bad) - (void)printf("\t<%g %g %g %g %g %g>", - facs.h, facs.k, facs.s, - facs.omega * RAD_TO_DEG, facs.a, facs.b); - else - (void)fputs("\t<* * * * * *>", stdout); - } - (void)fputs(bin_in ? "\n" : s, stdout); - } + +/* file processing function */ +static void process(FILE *fid) { + char line[MAX_LINE+3], *s = 0, pline[40]; + projUV data; + + for (;;) { + ++emess_dat.File_line; + + if (bin_in) { /* binary input */ + if (fread(&data, sizeof(projUV), 1, fid) != 1) + break; + } else { /* ascii input */ + if (!(s = fgets(line, MAX_LINE, fid))) + break; + + if (!strchr(s, '\n')) { /* overlong line */ + int c; + (void)strcat(s, "\n"); + /* gobble up to newline */ + while ((c = fgetc(fid)) != EOF && c != '\n') ; + } + + if (*s == tag) { + if (!bin_out) + (void)fputs(line, stdout); + continue; + } + + if (reversein) { + data.v = (*informat)(s, &s); + data.u = (*informat)(s, &s); + } else { + data.u = (*informat)(s, &s); + data.v = (*informat)(s, &s); + } + + if (data.v == HUGE_VAL) + data.u = HUGE_VAL; + + if (!*s && (s > line)) --s; /* assumed we gobbled \n */ + if (!bin_out && echoin) { + char t; + t = *s; + *s = '\0'; + (void)fputs(line, stdout); + *s = t; + putchar('\t'); + } + } + + if (data.u != HUGE_VAL) { + if (prescale) { data.u *= fscale; data.v *= fscale; } + if (dofactors && !inverse) + facs_bad = pj_factors(data, Proj, 0., &facs); + data = (*proj)(data, Proj); + + if (dofactors && inverse) + facs_bad = pj_factors(data, Proj, 0., &facs); + + if (postscale && data.u != HUGE_VAL) + { data.u *= fscale; data.v *= fscale; } + } + + if (bin_out) { /* binary output */ + (void)fwrite(&data, sizeof(projUV), 1, stdout); + continue; + } else if (data.u == HUGE_VAL) /* error output */ + (void)fputs(oterr, stdout); + else if (inverse && !oform) { /*ascii DMS output */ + if (reverseout) { + (void)fputs(rtodms(pline, data.v, 'N', 'S'), stdout); + putchar('\t'); + (void)fputs(rtodms(pline, data.u, 'E', 'W'), stdout); + } else { + (void)fputs(rtodms(pline, data.u, 'E', 'W'), stdout); + putchar('\t'); + (void)fputs(rtodms(pline, data.v, 'N', 'S'), stdout); + } + } else { /* x-y or decimal degree ascii output */ + if (inverse) { + data.v *= RAD_TO_DEG; + data.u *= RAD_TO_DEG; + } + + if (reverseout) { + (void)printf(oform,data.v); putchar('\t'); + (void)printf(oform,data.u); + } else { + (void)printf(oform,data.u); putchar('\t'); + (void)printf(oform,data.v); + } + } + + /* print scale factor data */ + if (dofactors) { + if (!facs_bad) + (void)printf("\t<%g %g %g %g %g %g>", + facs.h, facs.k, facs.s, + facs.omega * RAD_TO_DEG, facs.a, facs.b); + else + (void)fputs("\t<* * * * * *>", stdout); + } + (void)fputs(bin_in ? "\n" : s, stdout); + } } - static void /* file processing function --- verbosely */ -vprocess(FILE *fid) { - char line[MAX_LINE+3], *s, pline[40]; - projUV dat_ll, dat_xy, temp; - int linvers; - - if (!oform) - oform = "%.3f"; - if (bin_in || bin_out) - emess(1,"binary I/O not available in -V option"); - for (;;) { - ++emess_dat.File_line; - if (!(s = fgets(line, MAX_LINE, fid))) - break; - if (!strchr(s, '\n')) { /* overlong line */ - int c; - (void)strcat(s, "\n"); - /* gobble up to newline */ - while ((c = fgetc(fid)) != EOF && c != '\n') ; - } - if (*s == tag) { /* pass on data */ - (void)fputs(s, stdout); - continue; - } - /* check to override default input mode */ - if (*s == 'I' || *s == 'i') { - linvers = 1; - ++s; - } else if (*s == 'I' || *s == 'i') { - linvers = 0; - ++s; - } else - linvers = inverse; - if (linvers) { - if (!PJ_INVERS(Proj)) { - emess(-1,"inverse for this projection not avail.\n"); - continue; - } - dat_xy.u = strtod(s, &s); - dat_xy.v = strtod(s, &s); - if (dat_xy.u == HUGE_VAL || dat_xy.v == HUGE_VAL) { - emess(-1,"lon-lat input conversion failure\n"); - continue; - } - if (prescale) { dat_xy.u *= fscale; dat_xy.v *= fscale; } - if (reversein) { - temp.u = dat_xy.u; - temp.v = dat_xy.v; - dat_xy.u = temp.v; - dat_xy.v = temp.u; - } - dat_ll = pj_inv(dat_xy, Proj); - } else { - dat_ll.u = dmstor(s, &s); - dat_ll.v = dmstor(s, &s); - if (dat_ll.u == HUGE_VAL || dat_ll.v == HUGE_VAL) { - emess(-1,"lon-lat input conversion failure\n"); - continue; - } - if (reversein) { - temp.u = dat_ll.u; - temp.v = dat_ll.v; - dat_ll.u = temp.v; - dat_ll.v = temp.u; - } - dat_xy = pj_fwd(dat_ll, Proj); - if (postscale) { dat_xy.u *= fscale; dat_xy.v *= fscale; } - } - /* For some reason pj_errno does not work as expected in some */ - /* versions of Visual Studio, so using pj_get_errno_ref instead */ - if (*pj_get_errno_ref()) { - emess(-1, pj_strerrno(*pj_get_errno_ref())); - continue; - } - if (!*s && (s > line)) --s; /* assumed we gobbled \n */ - if (pj_factors(dat_ll, Proj, 0., &facs)) { - emess(-1,"failed to compute factors\n\n"); - continue; - } - if (*s != '\n') - (void)fputs(s, stdout); - (void)fputs("Longitude: ", stdout); - (void)fputs(rtodms(pline, dat_ll.u, 'E', 'W'), stdout); - (void)printf(" [ %.11g ]\n", dat_ll.u * RAD_TO_DEG); - (void)fputs("Latitude: ", stdout); - (void)fputs(rtodms(pline, dat_ll.v, 'N', 'S'), stdout); - (void)printf(" [ %.11g ]\n", dat_ll.v * RAD_TO_DEG); - (void)fputs("Easting (x): ", stdout); - (void)printf(oform, dat_xy.u); putchar('\n'); - (void)fputs("Northing (y): ", stdout); - (void)printf(oform, dat_xy.v); putchar('\n'); - (void)printf("Meridian scale (h)%c: %.8f ( %.4g %% error )\n", - facs.code & IS_ANAL_HK ? '*' : ' ', facs.h, (facs.h-1.)*100.); - (void)printf("Parallel scale (k)%c: %.8f ( %.4g %% error )\n", - facs.code & IS_ANAL_HK ? '*' : ' ', facs.k, (facs.k-1.)*100.); - (void)printf("Areal scale (s): %.8f ( %.4g %% error )\n", - facs.s, (facs.s-1.)*100.); - (void)printf("Angular distortion (w): %.3f\n", facs.omega * - RAD_TO_DEG); - (void)printf("Meridian/Parallel angle: %.5f\n", - facs.thetap * RAD_TO_DEG); - (void)printf("Convergence%c: ",facs.code & IS_ANAL_CONV ? '*' : ' '); - (void)fputs(rtodms(pline, facs.conv, 0, 0), stdout); - (void)printf(" [ %.8f ]\n", facs.conv * RAD_TO_DEG); - (void)printf("Max-min (Tissot axis a-b) scale error: %.5f %.5f\n\n", - facs.a, facs.b); - } + +/* file processing function --- verbosely */ +static void vprocess(FILE *fid) { + char line[MAX_LINE+3], *s, pline[40]; + projUV dat_ll, dat_xy, temp; + int linvers; + + if (!oform) + oform = "%.3f"; + + if (bin_in || bin_out) + emess(1,"binary I/O not available in -V option"); + + for (;;) { + ++emess_dat.File_line; + + if (!(s = fgets(line, MAX_LINE, fid))) + break; + + if (!strchr(s, '\n')) { /* overlong line */ + int c; + (void)strcat(s, "\n"); + /* gobble up to newline */ + while ((c = fgetc(fid)) != EOF && c != '\n') ; + } + + if (*s == tag) { /* pass on data */ + (void)fputs(s, stdout); + continue; + } + + /* check to override default input mode */ + if (*s == 'I' || *s == 'i') { + linvers = 1; + ++s; + } else if (*s == 'I' || *s == 'i') { + linvers = 0; + ++s; + } else + linvers = inverse; + + if (linvers) { + if (!PJ_INVERS(Proj)) { + emess(-1,"inverse for this projection not avail.\n"); + continue; + } + dat_xy.u = strtod(s, &s); + dat_xy.v = strtod(s, &s); + if (dat_xy.u == HUGE_VAL || dat_xy.v == HUGE_VAL) { + emess(-1,"lon-lat input conversion failure\n"); + continue; + } + if (prescale) { dat_xy.u *= fscale; dat_xy.v *= fscale; } + if (reversein) { + temp.u = dat_xy.u; + temp.v = dat_xy.v; + dat_xy.u = temp.v; + dat_xy.v = temp.u; + } + dat_ll = pj_inv(dat_xy, Proj); + } else { + dat_ll.u = dmstor(s, &s); + dat_ll.v = dmstor(s, &s); + if (dat_ll.u == HUGE_VAL || dat_ll.v == HUGE_VAL) { + emess(-1,"lon-lat input conversion failure\n"); + continue; + } + if (reversein) { + temp.u = dat_ll.u; + temp.v = dat_ll.v; + dat_ll.u = temp.v; + dat_ll.v = temp.u; + } + dat_xy = pj_fwd(dat_ll, Proj); + if (postscale) { dat_xy.u *= fscale; dat_xy.v *= fscale; } + } + + /* For some reason pj_errno does not work as expected in some */ + /* versions of Visual Studio, so using pj_get_errno_ref instead */ + if (*pj_get_errno_ref()) { + emess(-1, pj_strerrno(*pj_get_errno_ref())); + continue; + } + + if (!*s && (s > line)) --s; /* assumed we gobbled \n */ + if (pj_factors(dat_ll, Proj, 0., &facs)) { + emess(-1,"failed to compute factors\n\n"); + continue; + } + + if (*s != '\n') + (void)fputs(s, stdout); + + (void)fputs("Longitude: ", stdout); + (void)fputs(rtodms(pline, dat_ll.u, 'E', 'W'), stdout); + (void)printf(" [ %.11g ]\n", dat_ll.u * RAD_TO_DEG); + (void)fputs("Latitude: ", stdout); + (void)fputs(rtodms(pline, dat_ll.v, 'N', 'S'), stdout); + (void)printf(" [ %.11g ]\n", dat_ll.v * RAD_TO_DEG); + (void)fputs("Easting (x): ", stdout); + (void)printf(oform, dat_xy.u); putchar('\n'); + (void)fputs("Northing (y): ", stdout); + (void)printf(oform, dat_xy.v); putchar('\n'); + (void)printf("Meridian scale (h)%c: %.8f ( %.4g %% error )\n", + facs.code & IS_ANAL_HK ? '*' : ' ', facs.h, (facs.h-1.)*100.); + (void)printf("Parallel scale (k)%c: %.8f ( %.4g %% error )\n", + facs.code & IS_ANAL_HK ? '*' : ' ', facs.k, (facs.k-1.)*100.); + (void)printf("Areal scale (s): %.8f ( %.4g %% error )\n", + facs.s, (facs.s-1.)*100.); + (void)printf("Angular distortion (w): %.3f\n", facs.omega * + RAD_TO_DEG); + (void)printf("Meridian/Parallel angle: %.5f\n", + facs.thetap * RAD_TO_DEG); + (void)printf("Convergence%c: ",facs.code & IS_ANAL_CONV ? '*' : ' '); + (void)fputs(rtodms(pline, facs.conv, 0, 0), stdout); + (void)printf(" [ %.8f ]\n", facs.conv * RAD_TO_DEG); + (void)printf("Max-min (Tissot axis a-b) scale error: %.5f %.5f\n\n", + facs.a, facs.b); + } } int main(int argc, char **argv) { @@ -273,6 +304,7 @@ int main(int argc, char **argv) { (void)fprintf(stderr, usage, pj_get_release(), emess_dat.Prog_name); exit (0); } + /* process run line arguments */ while (--argc > 0) { /* collect run line arguments */ if(**++argv == '-') for(arg = *argv;;) { @@ -459,6 +491,7 @@ int main(int argc, char **argv) { gen_cheb(inverse, int_proj, cheby_str, Proj, iargc, iargv); exit(0); } + /* set input formatting control */ if (mon) { pj_pr_list(Proj); @@ -477,6 +510,7 @@ int main(int argc, char **argv) { } } } + if (inverse) informat = strtod; else { @@ -485,8 +519,7 @@ int main(int argc, char **argv) { oform = "%.2f"; } - if (bin_out) - { + if (bin_out) { SET_BINARY_MODE(stdout); } @@ -516,7 +549,9 @@ int main(int argc, char **argv) { (void)fclose(fid); emess_dat.File_name = 0; } + if( Proj ) pj_free(Proj); + exit(0); /* normal completion */ } -- cgit v1.2.3 From d55c25c7f639f91cfd2e6ef9bdef0c68d9e93289 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 5 Sep 2017 12:19:12 +0200 Subject: PJ_unitconvert: fix memory leak. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3288. Credit to OSS Fuzz --- src/PJ_unitconvert.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PJ_unitconvert.c b/src/PJ_unitconvert.c index 27672c8d..1e4cb839 100644 --- a/src/PJ_unitconvert.c +++ b/src/PJ_unitconvert.c @@ -200,6 +200,8 @@ static void *freeup_msg (PJ *P, int errlev) { if (0!=P->ctx) pj_ctx_set_errno (P->ctx, errlev); + pj_dealloc (P->opaque); + return pj_dealloc(P); } -- cgit v1.2.3 From 1c743de193f43f818635235d60330e78dbd4cd96 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 5 Sep 2017 13:13:52 +0200 Subject: proj: Do rad->deg conversion if output units warrants it. With the introduction of transformation pipelines it is possible to create a pipeline that has degrees as it's output unit. If that is the case the output coordinate will be in radians internally. This commit makes sure that a conversion to degrees is applied before printing to stdout. --- src/proj.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/proj.c b/src/proj.c index 70ca4033..aa0f07c0 100644 --- a/src/proj.c +++ b/src/proj.c @@ -143,10 +143,17 @@ static void process(FILE *fid) { putchar('\t'); (void)fputs(rtodms(pline, data.v, 'N', 'S'), stdout); } - } else { /* x-y or decimal degree ascii output */ + } else { /* x-y or decimal degree ascii output, scale if warranted by output units */ if (inverse) { - data.v *= RAD_TO_DEG; - data.u *= RAD_TO_DEG; + if (Proj->left == PJ_IO_UNITS_RADIANS || Proj->left == PJ_IO_UNITS_CLASSIC) { + data.v *= RAD_TO_DEG; + data.u *= RAD_TO_DEG; + } + } else { + if (Proj->right == PJ_IO_UNITS_RADIANS) { + data.v *= RAD_TO_DEG; + data.u *= RAD_TO_DEG; + } } if (reverseout) { @@ -177,6 +184,7 @@ static void vprocess(FILE *fid) { projUV dat_ll, dat_xy, temp; int linvers; + if (!oform) oform = "%.3f"; @@ -247,6 +255,12 @@ static void vprocess(FILE *fid) { if (postscale) { dat_xy.u *= fscale; dat_xy.v *= fscale; } } + /* apply rad->deg scaling in case the output from a pipeline has degrees as units */ + if (!inverse && Proj->right == PJ_IO_UNITS_RADIANS) { + dat_xy.u *= RAD_TO_DEG; + dat_xy.v *= RAD_TO_DEG; + } + /* For some reason pj_errno does not work as expected in some */ /* versions of Visual Studio, so using pj_get_errno_ref instead */ if (*pj_get_errno_ref()) { -- cgit v1.2.3 From cf9401abeeb15be0d4d886e4aabbce6c19245fd2 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 6 Sep 2017 16:31:02 +0200 Subject: Add PJ_FACTORS bit flags to proj.h --- src/proj.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/proj.h b/src/proj.h index 1d6191fd..3b4a1a67 100644 --- a/src/proj.h +++ b/src/proj.h @@ -304,6 +304,10 @@ struct PJ_FACTORS { int code; /* info as to analytics, see following */ }; +#define PJ_IS_ANAL_XL_YL 01 /* derivatives of lon analytic */ +#define PJ_IS_ANAL_XP_YP 02 /* derivatives of lat analytic */ +#define PJ_IS_ANAL_HK 04 /* h and k analytic */ +#define PJ_IS_ANAL_CONV 010 /* convergence analytic */ struct PJ_INFO { char release[64]; /* Release info. Version + date */ -- cgit v1.2.3 From 14710d9989c731b2f51b0d309b0e97bc30ad2339 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 7 Sep 2017 16:51:39 +0200 Subject: PJ_ob_tran: fix potential memory leak. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3321. Credit to OSS Fuzz --- src/PJ_ob_tran.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/PJ_ob_tran.c b/src/PJ_ob_tran.c index 238dba67..a610a1fe 100644 --- a/src/PJ_ob_tran.c +++ b/src/PJ_ob_tran.c @@ -87,7 +87,14 @@ static void *freeup_new (PJ *P) { /* Destructor */ return pj_dealloc (P); if (P->opaque->link) - P->opaque->link->pfree(P->opaque->link); + { + /* This is a bit tricky: the linked PJ* shares the same params as */ + /* the current one, so unset it to avoid double free */ + /* We used to call P->opaque->link->pfree(P->opaque->link); only */ + /* but this leaked grids */ + P->opaque->link->params = NULL; + pj_free(P->opaque->link); + } pj_dealloc (P->opaque); return pj_dealloc(P); -- cgit v1.2.3 From 5e97ef560034cb0ae2aec9613a5ff7695b1704c5 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Sat, 9 Sep 2017 11:16:40 +0200 Subject: Tested for wrong indices before array lookup. Fixes #566. --- src/PJ_unitconvert.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PJ_unitconvert.c b/src/PJ_unitconvert.c index 27672c8d..49bb6556 100644 --- a/src/PJ_unitconvert.c +++ b/src/PJ_unitconvert.c @@ -309,9 +309,9 @@ static PJ_OBS reverse_obs(PJ_OBS obs, PJ *P) { /* delegate unit conversion of physical dimensions to the 3D function */ out.coo.lpz = reverse_3d(obs.coo.xyz, P); - if (Q->t_in_id >= 0) - out.coo.xyzt.t = time_units[Q->t_out_id].t_in( obs.coo.xyzt.t ); if (Q->t_out_id >= 0) + out.coo.xyzt.t = time_units[Q->t_out_id].t_in( obs.coo.xyzt.t ); + if (Q->t_in_id >= 0) out.coo.xyzt.t = time_units[Q->t_in_id].t_out( out.coo.xyzt.t ); return out; -- cgit v1.2.3 From f5cb9ad88904904f62c6f1718aadd1dc447ee133 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Sat, 9 Sep 2017 14:47:30 +0200 Subject: Potential fix for pip3 failure on travis, as suggested in https://github.com/travis-ci/travis-ci/issues/8363 --- travis/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/travis/install.sh b/travis/install.sh index 70b8e90d..6eddb4bf 100755 --- a/travis/install.sh +++ b/travis/install.sh @@ -84,6 +84,7 @@ PROJ_LIB=$GRIDDIR ./src/proj -VC # install & run the working GIGS test # create locations that pyproj understands +pyenv global system 3.4 python3 --version ln -s src include ln -s src/.libs lib -- cgit v1.2.3 From 647f4012e4f8da4c2bf25b1f13588c10e543b807 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Mon, 11 Sep 2017 13:35:31 +0200 Subject: Select python version via travis setup instead of using pyenv (which is not consistent across platforms) --- .travis.yml | 3 +++ travis/install.sh | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 31ab75d0..89b4c4b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,9 @@ matrix: - BUILD_NAME=mingw32 - DETAILS="mingw32" +python: + - 3.6 + # allow_failures: # - os: osx diff --git a/travis/install.sh b/travis/install.sh index 6eddb4bf..70b8e90d 100755 --- a/travis/install.sh +++ b/travis/install.sh @@ -84,7 +84,6 @@ PROJ_LIB=$GRIDDIR ./src/proj -VC # install & run the working GIGS test # create locations that pyproj understands -pyenv global system 3.4 python3 --version ln -s src include ln -s src/.libs lib -- cgit v1.2.3 From 03116f07b8c3abd2446f8887536b997cabd09ca0 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Mon, 11 Sep 2017 16:30:52 +0200 Subject: Set python version to 3.6 with pyenv --- travis/before_install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/travis/before_install.sh b/travis/before_install.sh index 8a4bbd24..d4a71766 100755 --- a/travis/before_install.sh +++ b/travis/before_install.sh @@ -1,5 +1,6 @@ #!/bin/bash +pyenv global system 3.6 pip install --user cpp-coveralls ./travis/docker.sh -- cgit v1.2.3 From 261c7497c793a8bad19bebf114294f8b54c47d68 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 12 Sep 2017 11:22:53 +0200 Subject: Move python version setup to build matrix. Different Travis platforms seem to have different setups. This *should* take care of the differing python setups between linux and osx. --- .travis.yml | 7 ++++--- travis/before_install.sh | 6 +++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 89b4c4b0..4a0a2a98 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ matrix: env: - BUILD_NAME=linux_gcc - DETAILS="linux, gcc" + - PY_VERSION=3.4 - os: linux compiler: clang language: c @@ -26,11 +27,13 @@ matrix: env: - BUILD_NAME=linux_clang - DETAILS="linux, clang" + - PY_VERSION=3.4 - os: osx language: c env: - BUILD_NAME=osx - DETAILS="osx" + - PY_VERSION=3.4 - os: linux compiler: gcc language: c @@ -38,9 +41,7 @@ matrix: env: - BUILD_NAME=mingw32 - DETAILS="mingw32" - -python: - - 3.6 + - PY_VERSION=3.4 # allow_failures: # - os: osx diff --git a/travis/before_install.sh b/travis/before_install.sh index d4a71766..e70a4f3e 100755 --- a/travis/before_install.sh +++ b/travis/before_install.sh @@ -1,6 +1,10 @@ #!/bin/bash -pyenv global system 3.6 +# Specify python version. This introduced because the +# Travis setup seems to vary between platforms. +pyenv global system $PY_VERSION +pyenv versions # a bit of debug info + pip install --user cpp-coveralls ./travis/docker.sh -- cgit v1.2.3 From 358438903e77d9a7d11d59b4bef85e834418266b Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 12 Sep 2017 12:38:26 +0200 Subject: Make sure all platform specific before_install scripts call the global before_install script. Python version setup moved to global before_install script. --- .travis.yml | 4 ---- travis/before_install.sh | 15 +++++++-------- travis/linux_clang/before_install.sh | 1 + travis/linux_gcc/before_install.sh | 6 +++++- travis/mingw32/before_install.sh | 2 ++ travis/osx/before_install.sh | 2 ++ 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4a0a2a98..31ab75d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,6 @@ matrix: env: - BUILD_NAME=linux_gcc - DETAILS="linux, gcc" - - PY_VERSION=3.4 - os: linux compiler: clang language: c @@ -27,13 +26,11 @@ matrix: env: - BUILD_NAME=linux_clang - DETAILS="linux, clang" - - PY_VERSION=3.4 - os: osx language: c env: - BUILD_NAME=osx - DETAILS="osx" - - PY_VERSION=3.4 - os: linux compiler: gcc language: c @@ -41,7 +38,6 @@ matrix: env: - BUILD_NAME=mingw32 - DETAILS="mingw32" - - PY_VERSION=3.4 # allow_failures: # - os: osx diff --git a/travis/before_install.sh b/travis/before_install.sh index e70a4f3e..12f2edba 100755 --- a/travis/before_install.sh +++ b/travis/before_install.sh @@ -1,11 +1,10 @@ #!/bin/bash -# Specify python version. This introduced because the -# Travis setup seems to vary between platforms. -pyenv global system $PY_VERSION -pyenv versions # a bit of debug info - -pip install --user cpp-coveralls -./travis/docker.sh - +# All platform-specific before_install scripts starts by running this +# "global" before_install script. +# Specify which version of python to use. The default python to use on Travis +# can vary from platform to platform, so we use pyenv to make sure we use +# a version that works for the complete build processs. +pyenv global system 3.4 +pyenv versions # a bit of debug info diff --git a/travis/linux_clang/before_install.sh b/travis/linux_clang/before_install.sh index 75acd97a..f6e21076 100755 --- a/travis/linux_clang/before_install.sh +++ b/travis/linux_clang/before_install.sh @@ -2,4 +2,5 @@ set -e +./travis/before_install.sh # do nothing diff --git a/travis/linux_gcc/before_install.sh b/travis/linux_gcc/before_install.sh index 31805e80..0c37643c 100755 --- a/travis/linux_gcc/before_install.sh +++ b/travis/linux_gcc/before_install.sh @@ -1,5 +1,7 @@ #!/bin/bash +./travis/before_install.sh + sudo apt-get install -y cppcheck cppcheck --inline-suppr --template='{file}:{line},{severity},{id},{message}' --enable=all --inconclusive --std=posix -DPJ_SELFTEST=1 src/*.c 2>/tmp/cppcheck.txt @@ -12,4 +14,6 @@ fi set -e -./travis/before_install.sh +pip install --user cpp-coveralls +./travis/docker.sh + diff --git a/travis/mingw32/before_install.sh b/travis/mingw32/before_install.sh index 18949b75..5cadb761 100755 --- a/travis/mingw32/before_install.sh +++ b/travis/mingw32/before_install.sh @@ -2,6 +2,8 @@ set -e +./travis/before_install.sh + sudo apt-get update -qq sudo apt-get install -qq wine sudo apt-get install -qq mingw32 diff --git a/travis/osx/before_install.sh b/travis/osx/before_install.sh index cd553dda..4ca62084 100755 --- a/travis/osx/before_install.sh +++ b/travis/osx/before_install.sh @@ -2,5 +2,7 @@ set -e +./travis/before_install.sh + brew install ccache brew install python3 -- cgit v1.2.3 From 2edafb2504e3b20da6033e4a396636cfe22942f2 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 12 Sep 2017 21:11:52 +0200 Subject: Change how existance of strings in info-structs are checked. Before this commit they always evaluated as true. Fixes #568. --- src/PJ_cart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PJ_cart.c b/src/PJ_cart.c index 1373e870..257d0dca 100644 --- a/src/PJ_cart.c +++ b/src/PJ_cart.c @@ -486,13 +486,13 @@ int pj_cart_selftest (void) { /* proj_info() */ /* this one is difficult to test, since the output changes with the setup */ info = proj_info(); - if (info.version) { + if (info.version[0] != '\0' ) { char tmpstr[64]; sprintf(tmpstr, "%d.%d.%d", info.major, info.minor, info.patch); if (strcmp(info.version, tmpstr)) return 55; } - if (!info.release) return 56; - if (!info.searchpath) return 57; + if (info.release[0] == '\0') return 56; + if (info.searchpath[0] == '\0') return 57; /* proj_pj_info() */ P = proj_create(0, "+proj=august"); /* august has no inverse */ -- cgit v1.2.3 From fe86f34556dfc4613347c41bb14e8ac025282627 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 13 Sep 2017 11:57:03 +0200 Subject: Add typedef for transformation direction enum --- src/PJ_horner.c | 6 +++--- src/pj_obs_api.c | 12 ++++++------ src/proj.h | 16 ++++++++-------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/PJ_horner.c b/src/PJ_horner.c index c6560d3a..43fe1896 100644 --- a/src/PJ_horner.c +++ b/src/PJ_horner.c @@ -94,7 +94,7 @@ PROJ_HEAD(horner, "Horner polynomial evaluation"); struct horner; typedef struct horner HORNER; -static UV horner (const HORNER *transformation, enum proj_direction, UV position); +static UV horner (const HORNER *transformation, PJ_DIRECTION direction, UV position); static HORNER *horner_alloc (size_t order, int complex_polynomia); static void horner_free (HORNER *h); @@ -178,7 +178,7 @@ static HORNER *horner_alloc (size_t order, int complex_polynomia) { /**********************************************************************/ -static UV horner (const HORNER *transformation, enum proj_direction direction, UV position) { +static UV horner (const HORNER *transformation, PJ_DIRECTION direction, UV position) { /*********************************************************************** A reimplementation of the classic Engsager/Poder 2D Horner polynomial @@ -303,7 +303,7 @@ static PJ_OBS horner_reverse_obs (PJ_OBS point, PJ *P) { /**********************************************************************/ -static UV complex_horner (const HORNER *transformation, enum proj_direction direction, UV position) { +static UV complex_horner (const HORNER *transformation, PJ_DIRECTION direction, UV position) { /*********************************************************************** A reimplementation of a classic Engsager/Poder Horner complex diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index b2929a07..90269764 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -90,7 +90,7 @@ double proj_xyz_dist (XYZ a, XYZ b) { /* Measure numerical deviation after n roundtrips fwd-inv (or inv-fwd) */ -double proj_roundtrip (PJ *P, enum proj_direction direction, int n, PJ_OBS obs) { +double proj_roundtrip (PJ *P, PJ_DIRECTION direction, int n, PJ_OBS obs) { int i; PJ_OBS o, u; @@ -125,7 +125,7 @@ double proj_roundtrip (PJ *P, enum proj_direction direction, int n, PJ_OBS obs) /* Apply the transformation P to the coordinate coo */ -PJ_OBS proj_trans_obs (PJ *P, enum proj_direction direction, PJ_OBS obs) { +PJ_OBS proj_trans_obs (PJ *P, PJ_DIRECTION direction, PJ_OBS obs) { if (0==P) return obs; @@ -147,7 +147,7 @@ PJ_OBS proj_trans_obs (PJ *P, enum proj_direction direction, PJ_OBS obs) { /* Apply the transformation P to the coordinate coo */ -PJ_COORD proj_trans_coord (PJ *P, enum proj_direction direction, PJ_COORD coo) { +PJ_COORD proj_trans_coord (PJ *P, PJ_DIRECTION direction, PJ_COORD coo) { if (0==P) return coo; @@ -171,7 +171,7 @@ PJ_COORD proj_trans_coord (PJ *P, enum proj_direction direction, PJ_COORD coo) { /*************************************************************************************/ size_t proj_transform ( PJ *P, - enum proj_direction direction, + PJ_DIRECTION direction, double *x, size_t sx, size_t nx, double *y, size_t sy, size_t ny, double *z, size_t sz, size_t nz, @@ -319,7 +319,7 @@ size_t proj_transform ( } /*****************************************************************************/ -int proj_transform_obs (PJ *P, enum proj_direction direction, size_t n, PJ_OBS *obs) { +int proj_transform_obs (PJ *P, PJ_DIRECTION direction, size_t n, PJ_OBS *obs) { /****************************************************************************** Batch transform an array of PJ_OBS. @@ -337,7 +337,7 @@ int proj_transform_obs (PJ *P, enum proj_direction direction, size_t n, PJ_OBS * } /*****************************************************************************/ -int proj_transform_coord (PJ *P, enum proj_direction direction, size_t n, PJ_COORD *coord) { +int proj_transform_coord (PJ *P, PJ_DIRECTION direction, size_t n, PJ_COORD *coord) { /****************************************************************************** Batch transform an array of PJ_COORD. diff --git a/src/proj.h b/src/proj.h index 3b4a1a67..c2eb3523 100644 --- a/src/proj.h +++ b/src/proj.h @@ -367,35 +367,35 @@ PJ *proj_destroy (PJ *P); /* Apply transformation to observation - in forward or inverse direction */ -enum proj_direction { +enum PJ_DIRECTION { PJ_FWD = 1, /* Forward */ PJ_IDENT = 0, /* Do nothing */ PJ_INV = -1 /* Inverse */ }; +typedef enum PJ_DIRECTION PJ_DIRECTION; - -PJ_OBS proj_trans_obs (PJ *P, enum proj_direction direction, PJ_OBS obs); -PJ_COORD proj_trans_coord (PJ *P, enum proj_direction direction, PJ_COORD coord); +PJ_OBS proj_trans_obs (PJ *P, PJ_DIRECTION direction, PJ_OBS obs); +PJ_COORD proj_trans_coord (PJ *P, PJ_DIRECTION direction, PJ_COORD coord); size_t proj_transform ( PJ *P, - enum proj_direction direction, + PJ_DIRECTION direction, double *x, size_t sx, size_t nx, double *y, size_t sy, size_t ny, double *z, size_t sz, size_t nz, double *t, size_t st, size_t nt ); -int proj_transform_obs (PJ *P, enum proj_direction direction, size_t n, PJ_OBS *obs); -int proj_transform_coord (PJ *P, enum proj_direction direction, size_t n, PJ_COORD *coord); +int proj_transform_obs (PJ *P, PJ_DIRECTION direction, size_t n, PJ_OBS *obs); +int proj_transform_coord (PJ *P, PJ_DIRECTION direction, size_t n, PJ_COORD *coord); /* Initializers */ PJ_COORD proj_coord (double x, double y, double z, double t); PJ_OBS proj_obs (double x, double y, double z, double t, double o, double p, double k, int id, unsigned int flags); /* Measure internal consistency - in forward or inverse direction */ -double proj_roundtrip (PJ *P, enum proj_direction direction, int n, PJ_OBS obs); +double proj_roundtrip (PJ *P, PJ_DIRECTION direction, int n, PJ_OBS obs); /* Geodesic distance between two points with angular 2D coordinates */ double proj_lp_dist (PJ *P, LP a, LP b); -- cgit v1.2.3 From e2faff822f2161d1a45b515d71edde54a19c48cb Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 13 Sep 2017 13:05:04 +0200 Subject: make PJ* P argument of proj_lp_dist const --- src/pj_obs_api.c | 2 +- src/proj.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index 90269764..6f9644b1 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -70,7 +70,7 @@ PJ_OBS proj_obs (double x, double y, double z, double t, double o, double p, dou /* Geodesic distance between two points with angular 2D coordinates */ -double proj_lp_dist (PJ *P, LP a, LP b) { +double proj_lp_dist (const PJ *P, LP a, LP b) { double s12, azi1, azi2; /* Note: the geodesic code takes arguments in degrees */ geod_inverse (P->geod, PJ_TODEG(a.phi), PJ_TODEG(a.lam), PJ_TODEG(b.phi), PJ_TODEG(b.lam), &s12, &azi1, &azi2); diff --git a/src/proj.h b/src/proj.h index c2eb3523..943c500f 100644 --- a/src/proj.h +++ b/src/proj.h @@ -398,7 +398,7 @@ PJ_OBS proj_obs (double x, double y, double z, double t, double o, double p, double proj_roundtrip (PJ *P, PJ_DIRECTION direction, int n, PJ_OBS obs); /* Geodesic distance between two points with angular 2D coordinates */ -double proj_lp_dist (PJ *P, LP a, LP b); +double proj_lp_dist (const PJ *P, LP a, LP b); /* Euclidean distance between two points with linear 2D coordinates */ double proj_xy_dist (XY a, XY b); @@ -415,8 +415,8 @@ void proj_errno_restore (PJ *P, int err); PJ_DERIVS proj_derivatives(const PJ *P, const LP lp); -PJ_FACTORS proj_factors(const PJ *P, const LP lp); - +PJ_FACTORS proj_factors(const PJ *P, const LP lp); + /* Info functions - get information about various PROJ.4 entities */ PJ_INFO proj_info(void); PJ_PROJ_INFO proj_pj_info(const PJ *P); -- cgit v1.2.3 From 6b07474e9427d53134e77f0bdf3ced7812d080c4 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 13 Sep 2017 13:27:14 +0200 Subject: Introduce PJ_DEFAULT_CTX constant that improves code readability --- src/PJ_cart.c | 18 +++++++++--------- src/PJ_hgridshift.c | 6 +++--- src/PJ_horner.c | 4 ++-- src/PJ_molodensky.c | 4 ++-- src/PJ_pipeline.c | 6 +++--- src/PJ_unitconvert.c | 4 ++-- src/PJ_vgridshift.c | 8 ++++---- src/proj.h | 2 ++ 8 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/PJ_cart.c b/src/PJ_cart.c index 257d0dca..d50036b5 100644 --- a/src/PJ_cart.c +++ b/src/PJ_cart.c @@ -253,7 +253,7 @@ int pj_cart_selftest (void) { char buf[40]; /* An utm projection on the GRS80 ellipsoid */ - P = proj_create (0, arg); + P = proj_create (PJ_DEFAULT_CTX, arg); if (0==P) return 1; @@ -262,7 +262,7 @@ int pj_cart_selftest (void) { proj_destroy (P); /* Same projection, now using argc/argv style initialization */ - P = proj_create_argv (0, 3, args); + P = proj_create_argv (PJ_DEFAULT_CTX, 3, args); if (0==P) return 2; @@ -306,7 +306,7 @@ int pj_cart_selftest (void) { proj_destroy (P); /* Now do some 3D transformations */ - P = proj_create (0, "+proj=cart +ellps=GRS80"); + P = proj_create (PJ_DEFAULT_CTX, "+proj=cart +ellps=GRS80"); if (0==P) return 6; @@ -374,7 +374,7 @@ int pj_cart_selftest (void) { /* Testing the proj_transform nightmare */ /* An utm projection on the GRS80 ellipsoid */ - P = proj_create (0, "+proj=utm +zone=32 +ellps=GRS80"); + P = proj_create (PJ_DEFAULT_CTX, "+proj=utm +zone=32 +ellps=GRS80"); if (0==P) return 13; @@ -457,7 +457,7 @@ int pj_cart_selftest (void) { proj_destroy (P); /* test proj_create_crs_to_crs() */ - P = proj_create_crs_to_crs(0, "epsg:25832", "epsg:25833"); + P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, "epsg:25832", "epsg:25833"); if (P==0) return 50; @@ -472,7 +472,7 @@ int pj_cart_selftest (void) { proj_destroy(P); /* let's make sure that only entries in init-files results in a usable PJ */ - P = proj_create_crs_to_crs(0, "proj=utm +zone=32 +datum=WGS84", "proj=utm +zone=33 +datum=WGS84"); + P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, "proj=utm +zone=32 +datum=WGS84", "proj=utm +zone=33 +datum=WGS84"); if (P != 0) { proj_destroy(P); return 52; @@ -495,11 +495,11 @@ int pj_cart_selftest (void) { if (info.searchpath[0] == '\0') return 57; /* proj_pj_info() */ - P = proj_create(0, "+proj=august"); /* august has no inverse */ + P = proj_create(PJ_DEFAULT_CTX, "+proj=august"); /* august has no inverse */ if (proj_pj_info(P).has_inverse) { proj_destroy(P); return 60; } proj_destroy(P); - P = proj_create(0, arg); + P = proj_create(PJ_DEFAULT_CTX, arg); pj_info = proj_pj_info(P); if ( !pj_info.has_inverse ) { proj_destroy(P); return 61; } if ( strcmp(pj_info.definition, arg) ) { proj_destroy(P); return 62; } @@ -539,7 +539,7 @@ int pj_cart_selftest (void) { /* test proj_derivatives_retrieve() and proj_factors_retrieve() */ - P = proj_create(0, "+proj=merc"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=merc"); a = proj_obs_null; a.coo.lp.lam = PJ_TORAD(12); a.coo.lp.phi = PJ_TORAD(55); diff --git a/src/PJ_hgridshift.c b/src/PJ_hgridshift.c index 674b4da8..4ee3fd42 100644 --- a/src/PJ_hgridshift.c +++ b/src/PJ_hgridshift.c @@ -110,18 +110,18 @@ int pj_hgridshift_selftest (void) { double dist; /* fail on purpose: +grids parameter is mandatory*/ - P = proj_create(0, "+proj=hgridshift"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=hgridshift"); if (0!=P) return 99; /* fail on purpose: open non-existing grid */ - P = proj_create(0, "+proj=hgridshift +grids=nonexistinggrid.gsb"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=hgridshift +grids=nonexistinggrid.gsb"); if (0!=P) return 999; /* Failure most likely means the grid is missing */ - P = proj_create (0, "+proj=hgridshift +grids=nzgd2kgrid0005.gsb +ellps=GRS80"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=hgridshift +grids=nzgd2kgrid0005.gsb +ellps=GRS80"); if (0==P) return 10; diff --git a/src/PJ_horner.c b/src/PJ_horner.c index 43fe1896..a9a618c7 100644 --- a/src/PJ_horner.c +++ b/src/PJ_horner.c @@ -529,7 +529,7 @@ int pj_horner_selftest (void) { double dist; /* Real polynonia relating the technical coordinate system TC32 to "System 45 Bornholm" */ - P = proj_create (0, tc32_utm32); + P = proj_create (PJ_DEFAULT_CTX, tc32_utm32); if (0==P) return 10; @@ -543,7 +543,7 @@ int pj_horner_selftest (void) { return 1; /* The complex polynomial transformation between the "System Storebaelt" and utm32/ed50 */ - P = proj_create (0, sb_utm32); + P = proj_create (PJ_DEFAULT_CTX, sb_utm32); if (0==P) return 11; diff --git a/src/PJ_molodensky.c b/src/PJ_molodensky.c index 49e27763..d9377234 100644 --- a/src/PJ_molodensky.c +++ b/src/PJ_molodensky.c @@ -338,7 +338,7 @@ int pj_molodensky_selftest (void) { PJ *P; /* Test the abridged Molodensky first. Example from appendix 3 of Deakin (2004). */ - P = proj_create(0, + P = proj_create(PJ_DEFAULT_CTX, "+proj=molodensky +a=6378160 +rf=298.25 " "+da=-23 +df=-8.120449e-8 +dx=-134 +dy=-48 +dz=149 " "+abridged " @@ -376,7 +376,7 @@ int pj_molodensky_selftest (void) { /* Test the abridged Molodensky first. Example from appendix 3 of Deaking (2004). */ - P = proj_create(0, + P = proj_create(PJ_DEFAULT_CTX, "+proj=molodensky +a=6378160 +rf=298.25 " "+da=-23 +df=-8.120449e-8 +dx=-134 +dy=-48 +dz=149 " ); diff --git a/src/PJ_pipeline.c b/src/PJ_pipeline.c index 6e42c0cb..a26f3ccf 100644 --- a/src/PJ_pipeline.c +++ b/src/PJ_pipeline.c @@ -526,7 +526,7 @@ int pj_pipeline_selftest (void) { double dist; /* forward-reverse geo->utm->geo */ - P = proj_create (0, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 +step +proj=utm +ellps=GRS80 +inv"); + P = proj_create (PJ_DEFAULT_CTX, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 +step +proj=utm +ellps=GRS80 +inv"); if (0==P) return 1000; /* zero initialize everything, then set (longitude, latitude, height) to (12, 55, 0) */ @@ -548,7 +548,7 @@ int pj_pipeline_selftest (void) { proj_destroy (P); /* And now the back-to-back situation utm->geo->utm */ - P = proj_create (0, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 +inv +step +proj=utm +ellps=GRS80"); + P = proj_create (PJ_DEFAULT_CTX, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 +inv +step +proj=utm +ellps=GRS80"); if (0==P) return 2000; @@ -572,7 +572,7 @@ int pj_pipeline_selftest (void) { /* Finally testing a corner case: A rather pointless one-step pipeline geo->utm */ - P = proj_create (0, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 "); + P = proj_create (PJ_DEFAULT_CTX, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 "); if (0==P) return 3000; diff --git a/src/PJ_unitconvert.c b/src/PJ_unitconvert.c index 06723399..7ce6035c 100644 --- a/src/PJ_unitconvert.c +++ b/src/PJ_unitconvert.c @@ -412,7 +412,7 @@ int pj_unitconvert_selftest (void) {return 0;} static int test_time(char* args, double tol, double t_in, double t_exp) { PJ_OBS in, out; - PJ *P = proj_create(0, args); + PJ *P = proj_create(PJ_DEFAULT_CTX, args); int ret = 0; if (P == 0) @@ -438,7 +438,7 @@ static int test_time(char* args, double tol, double t_in, double t_exp) { static int test_xyz(char* args, double tol, PJ_TRIPLET in, PJ_TRIPLET exp) { PJ_OBS out, obs_in; - PJ *P = proj_create(0, args); + PJ *P = proj_create(PJ_DEFAULT_CTX, args); int ret = 0; if (P == 0) diff --git a/src/PJ_vgridshift.c b/src/PJ_vgridshift.c index e790cd4d..0f031d4f 100644 --- a/src/PJ_vgridshift.c +++ b/src/PJ_vgridshift.c @@ -112,18 +112,18 @@ int pj_vgridshift_selftest (void) { PJ_OBS expect, a, b; double dist; - /* fail on purpose: +grids parameter it mandatory*/ - P = proj_create(0, "+proj=vgridshift"); + /* fail on purpose: +grids parameter is mandatory*/ + P = proj_create(PJ_DEFAULT_CTX, "+proj=vgridshift"); if (0!=P) return 99; /* fail on purpose: open non-existing grid */ - P = proj_create(0, "+proj=vgridshift +grids=nonexistinggrid.gtx"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=vgridshift +grids=nonexistinggrid.gtx"); if (0!=P) return 999; /* Failure most likely means the grid is missing */ - P = proj_create (0, "+proj=vgridshift +grids=egm96_15.gtx +ellps=GRS80"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=vgridshift +grids=egm96_15.gtx +ellps=GRS80"); if (0==P) return 10; diff --git a/src/proj.h b/src/proj.h index 943c500f..badde4cc 100644 --- a/src/proj.h +++ b/src/proj.h @@ -355,10 +355,12 @@ typedef struct projCtx_t PJ_CONTEXT; /* Functionality for handling thread contexts */ +#define PJ_DEFAULT_CTX 0 PJ_CONTEXT *proj_context_create (void); void proj_context_destroy (PJ_CONTEXT *ctx); + /* Manage the transformation definition object PJ */ PJ *proj_create (PJ_CONTEXT *ctx, const char *definition); PJ *proj_create_argv (PJ_CONTEXT *ctx, int argc, char **argv); -- cgit v1.2.3 From 9755994609973ee5325530052a241f85469da864 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 13 Sep 2017 13:41:00 +0200 Subject: Make proj_destroy and proj_context_destroy behave in the same way. --- src/pj_obs_api.c | 7 ++++--- src/proj.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index 6f9644b1..df8cfa3d 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -501,15 +501,16 @@ PJ_CONTEXT *proj_context_create (void) { } -void proj_context_destroy (PJ_CONTEXT *ctx) { +PJ_CONTEXT *proj_context_destroy (PJ_CONTEXT *ctx) { if (0==ctx) - return; + return 0; /* Trying to free the default context is a no-op (since it is statically allocated) */ if (pj_get_default_ctx ()==ctx) - return; + return 0; pj_ctx_free (ctx); + return 0; } diff --git a/src/proj.h b/src/proj.h index badde4cc..e1990e34 100644 --- a/src/proj.h +++ b/src/proj.h @@ -357,7 +357,7 @@ typedef struct projCtx_t PJ_CONTEXT; /* Functionality for handling thread contexts */ #define PJ_DEFAULT_CTX 0 PJ_CONTEXT *proj_context_create (void); -void proj_context_destroy (PJ_CONTEXT *ctx); +PJ_CONTEXT *proj_context_destroy (PJ_CONTEXT *ctx); -- cgit v1.2.3 From abdbb957e04b1c35297dd5cf4b8fb01097af5737 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 20 Sep 2017 14:11:09 +0200 Subject: Use pip instead of pip3. pyevn should enforce usage of python3-compatible version of pip. --- travis/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis/install.sh b/travis/install.sh index 70b8e90d..f21abc79 100755 --- a/travis/install.sh +++ b/travis/install.sh @@ -92,7 +92,7 @@ ln -s nad share/proj pwd # install pyproj export CFLAGS= -PROJ_DIR=`pwd` pip3 install -v --user pyproj +PROJ_DIR=`pwd` pip install -v --user pyproj cd test/gigs # run test_json.py -- cgit v1.2.3 From f614731e180af45151820dadac7f1c686d3c0823 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 20 Sep 2017 15:02:42 +0200 Subject: Use python 3.5 with pyenv --- travis/before_install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis/before_install.sh b/travis/before_install.sh index 12f2edba..1404eae3 100755 --- a/travis/before_install.sh +++ b/travis/before_install.sh @@ -6,5 +6,5 @@ # Specify which version of python to use. The default python to use on Travis # can vary from platform to platform, so we use pyenv to make sure we use # a version that works for the complete build processs. -pyenv global system 3.4 +pyenv global system 3.5 pyenv versions # a bit of debug info -- cgit v1.2.3 From f73859b91a20ae6299dcde08b2327b241be8226f Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 20 Sep 2017 15:57:40 +0200 Subject: Revert to using pip3 --- travis/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis/install.sh b/travis/install.sh index f21abc79..70b8e90d 100755 --- a/travis/install.sh +++ b/travis/install.sh @@ -92,7 +92,7 @@ ln -s nad share/proj pwd # install pyproj export CFLAGS= -PROJ_DIR=`pwd` pip install -v --user pyproj +PROJ_DIR=`pwd` pip3 install -v --user pyproj cd test/gigs # run test_json.py -- cgit v1.2.3 From 7db3acd2df38508e107209c912ac0b5ce2663f9c Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Thu, 21 Sep 2017 13:23:42 +0200 Subject: Use Python2 in favour of Python3 which behaves inconsistenly on Travis (#573) --- travis/before_install.sh | 16 +++++++++++++--- travis/install.sh | 7 +++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/travis/before_install.sh b/travis/before_install.sh index 1404eae3..249cb591 100755 --- a/travis/before_install.sh +++ b/travis/before_install.sh @@ -5,6 +5,16 @@ # Specify which version of python to use. The default python to use on Travis # can vary from platform to platform, so we use pyenv to make sure we use -# a version that works for the complete build processs. -pyenv global system 3.5 -pyenv versions # a bit of debug info +# a version that works for the complete build processs. (Not in use at the moment, +# since the pyenv setup on Travis is not consistent across platforms and partly +# broken as well) +#pyenv global system 3.5 +#pyenv versions # a bit of debug info + +# What is the current python setup? +which python +python --version +python3 --version + +which pip +pip --version diff --git a/travis/install.sh b/travis/install.sh index 70b8e90d..51a8ea2f 100755 --- a/travis/install.sh +++ b/travis/install.sh @@ -84,7 +84,6 @@ PROJ_LIB=$GRIDDIR ./src/proj -VC # install & run the working GIGS test # create locations that pyproj understands -python3 --version ln -s src include ln -s src/.libs lib mkdir share @@ -92,12 +91,12 @@ ln -s nad share/proj pwd # install pyproj export CFLAGS= -PROJ_DIR=`pwd` pip3 install -v --user pyproj +PROJ_DIR=`pwd` pip install -v --user pyproj cd test/gigs # run test_json.py -PROJ_LIB=../../nad python3 test_json.py --test conversion 5101.1-jhs.json 5101.4-jhs-etmerc.json 5105.2.json 5106.json 5108.json 5110.json 5111.1.json -PROJ_LIB=../../nad python3 test_json.py 5101.2-jhs.json 5101.3-jhs.json 5102.1.json 5103.1.json 5103.2.json 5103.3.json 5107.json 5109.json 5112.json 5113.json 5201.json 5208.json +PROJ_LIB=../../nad python test_json.py --test conversion 5101.1-jhs.json 5101.4-jhs-etmerc.json 5105.2.json 5106.json 5108.json 5110.json 5111.1.json +PROJ_LIB=../../nad python test_json.py 5101.2-jhs.json 5101.3-jhs.json 5102.1.json 5103.1.json 5103.2.json 5103.3.json 5107.json 5109.json 5112.json 5113.json 5201.json 5208.json cd ../.. mv src/.libs/*.gc* src -- cgit v1.2.3 From 33175ead05bf03853ab8a33372602160cf69d745 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Thu, 21 Sep 2017 21:10:07 +0200 Subject: Use FACTORS and DERIVS structs from projects.h instead of duplicating them in proj.h --- src/pj_obs_api.c | 6 ++---- src/proj.h | 24 ++++-------------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index df8cfa3d..54c75f45 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -740,8 +740,7 @@ PJ_DERIVS proj_derivatives(const PJ *P, const LP lp) { ******************************************************************************/ PJ_DERIVS derivs; - /* casting to struct DERIVS for compatibility reasons */ - if (pj_deriv(lp, 1e-5, (PJ *)P, (struct DERIVS *)&derivs)) { + if (pj_deriv(lp, 1e-5, (PJ *)P, &derivs)) { /* errno set in pj_derivs */ memset(&derivs, 0, sizeof(PJ_DERIVS)); } @@ -767,8 +766,7 @@ PJ_FACTORS proj_factors(const PJ *P, const LP lp) { /* pj_factors rely code being zero */ factors.code = 0; - /* casting to struct FACTORS for compatibility reasons */ - if (pj_factors(lp, (PJ *)P, 0.0, (struct FACTORS *)&factors)) { + if (pj_factors(lp, (PJ *)P, 0.0, &factors)) { /* errno set in pj_factors */ memset(&factors, 0, sizeof(PJ_FACTORS)); } diff --git a/src/proj.h b/src/proj.h index e1990e34..140ba320 100644 --- a/src/proj.h +++ b/src/proj.h @@ -182,11 +182,11 @@ typedef union PJ_TRIPLET PJ_TRIPLET; union PJ_COORD; typedef union PJ_COORD PJ_COORD; -struct PJ_DERIVS; -typedef struct PJ_DERIVS PJ_DERIVS; +struct DERIVS; +typedef struct DERIVS PJ_DERIVS; -struct PJ_FACTORS; -typedef struct PJ_FACTORS PJ_FACTORS; +struct FACTORS; +typedef struct FACTORS PJ_FACTORS; /* Data type for projection/transformation information */ struct PJconsts; @@ -288,22 +288,6 @@ struct PJ_OBS { unsigned int flags; /* additional data, intended for flags */ }; - -struct PJ_DERIVS { - double x_l, x_p; /* derivatives of x for lambda-phi */ - double y_l, y_p; /* derivatives of y for lambda-phi */ -}; - -struct PJ_FACTORS { - struct PJ_DERIVS der; - double h, k; /* meridional, parallel scales */ - double omega, thetap; /* angular distortion, theta prime */ - double conv; /* convergence */ - double s; /* areal scale factor */ - double a, b; /* max-min scale error */ - int code; /* info as to analytics, see following */ -}; - #define PJ_IS_ANAL_XL_YL 01 /* derivatives of lon analytic */ #define PJ_IS_ANAL_XP_YP 02 /* derivatives of lat analytic */ #define PJ_IS_ANAL_HK 04 /* h and k analytic */ -- cgit v1.2.3 From dd12554da8979e47be1eb1b8654c980865da654d Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Thu, 21 Sep 2017 21:18:59 +0200 Subject: Changed a few occurences of 'const PJ*' to just 'PJ*' since they were making promises that couldn't be kept --- src/pj_obs_api.c | 12 ++++++------ src/proj.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index 54c75f45..a6cb2623 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -583,7 +583,7 @@ PJ_INFO proj_info(void) { /*****************************************************************************/ -PJ_PROJ_INFO proj_pj_info(const PJ *P) { +PJ_PROJ_INFO proj_pj_info(PJ *P) { /****************************************************************************** Basic info about a particular instance of a projection object. @@ -607,7 +607,7 @@ PJ_PROJ_INFO proj_pj_info(const PJ *P) { pj_strlcpy(info.description, P->descr, sizeof(info.description)); /* projection definition */ - def = pj_get_def((PJ *)P, 0); /* pj_get_def takes a non-const PJ pointer */ + def = pj_get_def(P, 0); /* pj_get_def takes a non-const PJ pointer */ pj_strlcpy(info.definition, &def[1], sizeof(info.definition)); /* def includes a leading space */ pj_dealloc(def); @@ -730,7 +730,7 @@ PJ_INIT_INFO proj_init_info(const char *initname){ /*****************************************************************************/ -PJ_DERIVS proj_derivatives(const PJ *P, const LP lp) { +PJ_DERIVS proj_derivatives(PJ *P, const LP lp) { /****************************************************************************** Derivatives of coordinates. @@ -740,7 +740,7 @@ PJ_DERIVS proj_derivatives(const PJ *P, const LP lp) { ******************************************************************************/ PJ_DERIVS derivs; - if (pj_deriv(lp, 1e-5, (PJ *)P, &derivs)) { + if (pj_deriv(lp, 1e-5, P, &derivs)) { /* errno set in pj_derivs */ memset(&derivs, 0, sizeof(PJ_DERIVS)); } @@ -750,7 +750,7 @@ PJ_DERIVS proj_derivatives(const PJ *P, const LP lp) { /*****************************************************************************/ -PJ_FACTORS proj_factors(const PJ *P, const LP lp) { +PJ_FACTORS proj_factors(PJ *P, const LP lp) { /****************************************************************************** Cartographic characteristics at point lp. @@ -766,7 +766,7 @@ PJ_FACTORS proj_factors(const PJ *P, const LP lp) { /* pj_factors rely code being zero */ factors.code = 0; - if (pj_factors(lp, (PJ *)P, 0.0, &factors)) { + if (pj_factors(lp, P, 0.0, &factors)) { /* errno set in pj_factors */ memset(&factors, 0, sizeof(PJ_FACTORS)); } diff --git a/src/proj.h b/src/proj.h index 140ba320..d344485d 100644 --- a/src/proj.h +++ b/src/proj.h @@ -400,12 +400,12 @@ int proj_errno_reset (PJ *P); void proj_errno_restore (PJ *P, int err); -PJ_DERIVS proj_derivatives(const PJ *P, const LP lp); -PJ_FACTORS proj_factors(const PJ *P, const LP lp); +PJ_DERIVS proj_derivatives(PJ *P, const LP lp); +PJ_FACTORS proj_factors(PJ *P, const LP lp); /* Info functions - get information about various PROJ.4 entities */ PJ_INFO proj_info(void); -PJ_PROJ_INFO proj_pj_info(const PJ *P); +PJ_PROJ_INFO proj_pj_info(PJ *P); PJ_GRID_INFO proj_grid_info(const char *gridname); PJ_INIT_INFO proj_init_info(const char *initname); -- cgit v1.2.3 From 6fb79f304faec4d036ea46f19aa197e8cc85fe2e Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Fri, 22 Sep 2017 08:51:43 +0200 Subject: Add 'expected accuracy' member to PJ_PROJ_INFO struct. --- src/pj_obs_api.c | 5 +++++ src/proj.h | 9 +++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index a6cb2623..5c9f398b 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -595,6 +595,11 @@ PJ_PROJ_INFO proj_pj_info(PJ *P) { memset(&info, 0, sizeof(PJ_PROJ_INFO)); + /* Expected accuracy of the transformation. Hardcoded for now, will be improved */ + /* later. Most likely to be used when a transformation is set up with */ + /* proj_create_crs_to_crs in a future version that leverages the EPSG database. */ + info.accuracy = -1.0; + if (!P) { return info; } diff --git a/src/proj.h b/src/proj.h index d344485d..600d5b30 100644 --- a/src/proj.h +++ b/src/proj.h @@ -305,10 +305,11 @@ struct PJ_INFO { }; struct PJ_PROJ_INFO { - char id[16]; /* Name of the projection in question */ - char description[128]; /* Description of the projection */ - char definition[512]; /* Projection definition */ - int has_inverse; /* 1 if an inverse mapping exists, 0 otherwise */ + char id[16]; /* Name of the projection in question */ + char description[128]; /* Description of the projection */ + char definition[512]; /* Projection definition */ + int has_inverse; /* 1 if an inverse mapping exists, 0 otherwise */ + double accuracy; /* Expected accuracy of the transformation. -1 if unknown. */ }; struct PJ_GRID_INFO { -- cgit v1.2.3 From 6ea5a3cbe601bc14cb18614fdaa97092abf96f3c Mon Sep 17 00:00:00 2001 From: Nicolas David Date: Mon, 25 Sep 2017 21:05:46 +0200 Subject: fix #560 install cmake config file to lib and use GNUInstallDirs on Unix (#561) * fix #560 install proj4-config.cmake to defaut path * add some variable and cmake option to specify where the cmake config file should be installed. * change project_root_dir use in project-config.cmake.in variable from hard coded path to computed path with file(RELATIVE_PATH) function. * Still use the old project-config.cmake/configure_file way of generate config file. A cleaner way could be to use the modern cmake export(target ..) * use GNUInstallDirs for default unix install path --- CMakeLists.txt | 1 + cmake/CMakeLists.txt | 14 ++++---------- cmake/Proj4InstallPath.cmake | 24 ++++++++++++++++++++---- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 702eafaf..d6bbe8ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,6 +128,7 @@ set(LIBDIR "${DEFAULT_LIBDIR}" CACHE PATH "The directory to install libraries in set(DATADIR "${DEFAULT_DATADIR}" CACHE PATH "The directory to install data files into.") set(DOCDIR "${DEFAULT_DOCDIR}" CACHE PATH "The directory to install doc files into.") set(INCLUDEDIR "${DEFAULT_INCLUDEDIR}" CACHE PATH "The directory to install includes into.") +set(CMAKECONFIGDIR "${DEFAULT_CMAKEDIR}" CACHE PATH "The directory to install cmake config files into.") ################################################################################# # Build configured components diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 742da0e9..0fcde0ca 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -2,13 +2,7 @@ # ${INSTALL_CMAKE_DIR} and @PROJECT_ROOT_DIR@ is the relative # path to the root from there. (Note that the whole install tree can # be relocated.) -if (NOT WIN32) - set (INSTALL_CMAKE_DIR "share/cmake/${PROJECT_NAME}") - set (PROJECT_ROOT_DIR "../../..") -else () - set (INSTALL_CMAKE_DIR "cmake") - set (PROJECT_ROOT_DIR "..") -endif () +file(RELATIVE_PATH PROJECT_ROOT_DIR ${CMAKE_INSTALL_PREFIX}/${CMAKECONFIGDIR} ${CMAKE_INSTALL_PREFIX}) string(TOLOWER "${PROJECT_NAME}" PROJECT_NAME_LOWER) configure_file (project-config.cmake.in project-config.cmake @ONLY) @@ -16,14 +10,14 @@ configure_file (project-config-version.cmake.in project-config-version.cmake @ONLY) install (FILES "${CMAKE_CURRENT_BINARY_DIR}/project-config.cmake" - DESTINATION "${INSTALL_CMAKE_DIR}" + DESTINATION "${CMAKECONFIGDIR}" RENAME "${PROJECT_NAME_LOWER}-config.cmake") install (FILES "${CMAKE_CURRENT_BINARY_DIR}/project-config-version.cmake" - DESTINATION "${INSTALL_CMAKE_DIR}" + DESTINATION "${CMAKECONFIGDIR}" RENAME "${PROJECT_NAME_LOWER}-config-version.cmake") # Make information about the cmake targets (the library and the tools) # available. install (EXPORT targets FILE ${PROJECT_NAME_LOWER}-targets.cmake - DESTINATION "${INSTALL_CMAKE_DIR}") + DESTINATION "${CMAKECONFIGDIR}") diff --git a/cmake/Proj4InstallPath.cmake b/cmake/Proj4InstallPath.cmake index da1491c0..04f24670 100644 --- a/cmake/Proj4InstallPath.cmake +++ b/cmake/Proj4InstallPath.cmake @@ -15,19 +15,29 @@ endif(UNIX) IF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - SET(CMAKE_INSTALL_PREFIX ${DEFAULT_PROJ_ROOT_DIR} CACHE PATH "Foo install + SET(CMAKE_INSTALL_PREFIX ${DEFAULT_PROJ_ROOT_DIR} CACHE PATH "Proj.4 install prefix" FORCE) ENDIF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) #TODO # for data install testing the PROJ_LIB envVar +string(TOLOWER "${PROJECT_NAME}" PROJECT_NAME_LOWER) if(WIN32) set(DEFAULT_BIN_SUBDIR bin) set(DEFAULT_LIB_SUBDIR local/lib) set(DEFAULT_DATA_SUBDIR share) set(DEFAULT_INCLUDE_SUBDIR local/include) set(DEFAULT_DOC_SUBDIR share/doc/proj) + set(DEFAULT_CMAKE_SUBDIR local/lib/cmake/${PROJECT_NAME_LOWER}) +elseif(UNIX) + include(GNUInstallDirs) + set(DEFAULT_BIN_SUBDIR ${CMAKE_INSTALL_BINDIR}) + set(DEFAULT_LIB_SUBDIR ${CMAKE_INSTALL_LIBDIR}) + set(DEFAULT_DATA_SUBDIR ${CMAKE_INSTALL_DATADIR}) + set(DEFAULT_INCLUDE_SUBDIR ${CMAKE_INSTALL_INCLUDEDIR}) + set(DEFAULT_DOC_SUBDIR ${CMAKE_INSTALL_DOCDIR}) + set(DEFAULT_CMAKE_SUBDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME_LOWER}) else() # Common locatoins for Unix and Mac OS X set(DEFAULT_BIN_SUBDIR bin) @@ -35,9 +45,11 @@ else() set(DEFAULT_DATA_SUBDIR share/proj) set(DEFAULT_DOC_SUBDIR doc/proj) set(DEFAULT_INCLUDE_SUBDIR include) + set(DEFAULT_DOC_SUBDIR share/doc/proj) + set(DEFAULT_CMAKE_SUBDIR lib/cmake/${PROJECT_NAME_LOWER}) endif() -# Locations are changeable by user to customize layout of PDAL installation +# Locations are changeable by user to customize layout of Proj.4 installation # (default values are platform-specific) set(PROJ_BIN_SUBDIR ${DEFAULT_BIN_SUBDIR} CACHE STRING "Subdirectory where executables will be installed") @@ -48,7 +60,9 @@ set(PROJ_INCLUDE_SUBDIR ${DEFAULT_INCLUDE_SUBDIR} CACHE STRING set(PROJ_DATA_SUBDIR ${DEFAULT_DATA_SUBDIR} CACHE STRING "Subdirectory where data will be installed") set(PROJ_DOC_SUBDIR ${DEFAULT_DOC_SUBDIR} CACHE STRING - "Subdirectory where data will be installed") + "Subdirectory where doc will be installed") +set(PROJ_CMAKE_SUBDIR ${DEFAULT_CMAKE_SUBDIR} CACHE STRING + "Subdirectory where cmake proj4-config file will be installed") # Mark *DIR variables as advanced and dedicated to use by power-users only. mark_as_advanced(PROJ_ROOT_DIR @@ -56,12 +70,14 @@ mark_as_advanced(PROJ_ROOT_DIR PROJ_LIB_SUBDIR PROJ_INCLUDE_SUBDIR PROJ_DATA_SUBDIR - PROJ_DOC_SUBDIR ) + PROJ_DOC_SUBDIR + PROJ_CMAKE_SUBDIR ) set(DEFAULT_BINDIR "${PROJ_BIN_SUBDIR}") set(DEFAULT_LIBDIR "${PROJ_LIB_SUBDIR}") set(DEFAULT_DATADIR "${PROJ_DATA_SUBDIR}") set(DEFAULT_DOCDIR "${PROJ_DOC_SUBDIR}") set(DEFAULT_INCLUDEDIR "${PROJ_INCLUDE_SUBDIR}") +set(DEFAULT_CMAKEDIR "${PROJ_CMAKE_SUBDIR}") -- cgit v1.2.3 From 41ac8f6b2c1c4b94873393df0b3fa595ff4f0b2d Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 27 Sep 2017 22:18:05 +0200 Subject: decimalyear_to_mjd(): avoid almost infinite loop in case of crazy input. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3449. Credit to OSS Fuzz --- src/PJ_unitconvert.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/PJ_unitconvert.c b/src/PJ_unitconvert.c index 7ce6035c..8581dcad 100644 --- a/src/PJ_unitconvert.c +++ b/src/PJ_unitconvert.c @@ -112,9 +112,16 @@ static double decimalyear_to_mjd(double decimalyear) { /*********************************************************************** Epoch of modified julian date is 1858-11-16 00:00 ************************************************************************/ - int year = (int)floor(decimalyear); - double fractional_year = decimalyear - year; - double mjd = (year - 1859)*365 + 14 + 31; + int year; + double fractional_year; + double mjd; + + if( decimalyear < -10000 || decimalyear > 10000 ) + return 0; + + year = (int)floor(decimalyear); + fractional_year = decimalyear - year; + mjd = (year - 1859)*365 + 14 + 31; mjd += fractional_year*days_in_year(year); /* take care of leap days */ -- cgit v1.2.3 From 4a48c99cf5f84cbdbfca6bdd7efd93c370ab5ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20=C5=81oskot?= Date: Wed, 27 Sep 2017 23:24:04 +0200 Subject: Ignore Visual Studio cruft and build directories and scripts (#581) build.local.sh and build.local.bat as as user-specific scripts Build directories: build, _build.{platform} or _build.{compiler} [ci skip] --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index ad74f230..e191b441 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ *~ +build.local.bat +build.local.sh Makefile Makefile.in CMakeFiles @@ -8,8 +10,10 @@ cmake_install.cmake install_manifest.txt cmake/project-config*.cmake +/.vs* /*.manifest /*.swp +/*build* /aclocal.m4 /autom4te.cache /config.cache -- cgit v1.2.3 From 1402ac196457fb99bb16962c0d1371b6885b44c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20=C5=81oskot?= Date: Wed, 27 Sep 2017 23:24:16 +0200 Subject: Add detection of MSVC 14.0 and 14.1+ to CMake configuration (#580) --- cmake/Proj4SystemInfo.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmake/Proj4SystemInfo.cmake b/cmake/Proj4SystemInfo.cmake index 294a50b2..fda57edb 100644 --- a/cmake/Proj4SystemInfo.cmake +++ b/cmake/Proj4SystemInfo.cmake @@ -50,6 +50,12 @@ if(WIN32) if(MSVC_VERSION EQUAL 1800) set(PROJ_COMPILER_NAME "msvc-12.0") #Visual Studio 2013 endif() + if(MSVC_VERSION EQUAL 1900) # CMake 3.1+ + set(PROJ_COMPILER_NAME "msvc-14.0") #Visual Studio 2015 + endif() + if(MSVC_VERSION GREATER 1900 AND MSVC_VERSION LESS 1920) # CMake 3.8+ + set(PROJ_COMPILER_NAME "msvc-14.1") #Visual Studio 2017 + endif() endif(MSVC) if(MINGW) -- cgit v1.2.3 From a90a9ec5daa335b8b5eb6c93e4f5a0e48ca5656e Mon Sep 17 00:00:00 2001 From: Howard Butler Date: Wed, 27 Sep 2017 16:25:39 -0500 Subject: CMake updates (#578) * install proj4 data in share/proj, not share/ * no need for CMP0022 policy anymore --- cmake/Proj4InstallPath.cmake | 8 ++++---- cmake/policies.cmake | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cmake/Proj4InstallPath.cmake b/cmake/Proj4InstallPath.cmake index 04f24670..b06777f4 100644 --- a/cmake/Proj4InstallPath.cmake +++ b/cmake/Proj4InstallPath.cmake @@ -19,7 +19,7 @@ IF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) prefix" FORCE) ENDIF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) -#TODO +#TODO # for data install testing the PROJ_LIB envVar string(TOLOWER "${PROJECT_NAME}" PROJECT_NAME_LOWER) @@ -34,7 +34,7 @@ elseif(UNIX) include(GNUInstallDirs) set(DEFAULT_BIN_SUBDIR ${CMAKE_INSTALL_BINDIR}) set(DEFAULT_LIB_SUBDIR ${CMAKE_INSTALL_LIBDIR}) - set(DEFAULT_DATA_SUBDIR ${CMAKE_INSTALL_DATADIR}) + set(DEFAULT_DATA_SUBDIR ${CMAKE_INSTALL_DATAROOTDIR}/proj) set(DEFAULT_INCLUDE_SUBDIR ${CMAKE_INSTALL_INCLUDEDIR}) set(DEFAULT_DOC_SUBDIR ${CMAKE_INSTALL_DOCDIR}) set(DEFAULT_CMAKE_SUBDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME_LOWER}) @@ -67,8 +67,8 @@ set(PROJ_CMAKE_SUBDIR ${DEFAULT_CMAKE_SUBDIR} CACHE STRING # Mark *DIR variables as advanced and dedicated to use by power-users only. mark_as_advanced(PROJ_ROOT_DIR PROJ_BIN_SUBDIR - PROJ_LIB_SUBDIR - PROJ_INCLUDE_SUBDIR + PROJ_LIB_SUBDIR + PROJ_INCLUDE_SUBDIR PROJ_DATA_SUBDIR PROJ_DOC_SUBDIR PROJ_CMAKE_SUBDIR ) diff --git a/cmake/policies.cmake b/cmake/policies.cmake index c16fbc12..e1bfd53b 100644 --- a/cmake/policies.cmake +++ b/cmake/policies.cmake @@ -1,5 +1,4 @@ if (CMAKE_MAJOR_VERSION GREATER 2) - cmake_policy(SET CMP0022 OLD) # interface link libraries cmake_policy(SET CMP0042 NEW) # osx rpath cmake_policy(SET CMP0011 NEW) # policy setting endif() -- cgit v1.2.3 From fa318ed5db0e00bf0a9fb3c18852efb44a095427 Mon Sep 17 00:00:00 2001 From: Thomas Knudsen Date: Wed, 27 Sep 2017 13:54:30 +0200 Subject: Support a default destructor for PJ objects --- src/pj_ctx.c | 2 ++ src/pj_init.c | 47 ++++++++--------------------------------- src/pj_malloc.c | 47 +++-------------------------------------- src/pj_obs_api.c | 39 +++++++++------------------------- src/projects.h | 64 +++++--------------------------------------------------- 5 files changed, 29 insertions(+), 170 deletions(-) diff --git a/src/pj_ctx.c b/src/pj_ctx.c index 89b2816f..32a3d690 100644 --- a/src/pj_ctx.c +++ b/src/pj_ctx.c @@ -38,6 +38,8 @@ static volatile int default_context_initialized = 0; projCtx pj_get_ctx( projPJ pj ) { + if (0==pj) + return pj_get_default_ctx (); return pj->ctx; } diff --git a/src/pj_init.c b/src/pj_init.c index 7448fdb6..08a302c6 100644 --- a/src/pj_init.c +++ b/src/pj_init.c @@ -769,8 +769,8 @@ bum_call: /* cleanup error return */ /* This is the application callable entry point for destroying */ /* a projection definition. It does work generic to all */ /* projection types, and then calls the projection specific */ -/* free function (P->pfree()) to do local work. This maps to */ -/* the FREEUP code in the individual projection source files. */ +/* free function (P->pfree()) to do local work. In most cases */ +/* P->pfree()==pj_default_destructor. */ /************************************************************************/ void @@ -784,15 +784,10 @@ pj_free(PJ *P) { pj_dalloc(t); } - /* free array of grid pointers if we have one */ - if( P->gridlist != NULL ) - pj_dalloc( P->gridlist ); - - if( P->vgridlist_geoid != NULL ) - pj_dalloc( P->vgridlist_geoid ); - - if( P->catalog_name != NULL ) - pj_dalloc( P->catalog_name ); + /* free grid lists */ + pj_dealloc( P->gridlist ); + pj_dealloc( P->vgridlist_geoid ); + pj_dealloc( P->catalog_name ); /* We used to call pj_dalloc( P->catalog ), but this will leak */ /* memory. The safe way to clear catalog and grid is to call */ @@ -800,34 +795,10 @@ pj_free(PJ *P) { /* TODO: we should probably have a public pj_cleanup() method to do all */ /* that */ - if( P->geod != NULL ) - pj_dalloc( P->geod ); + /* free the interface to Charles Karney's geodesic library */ + pj_dealloc( P->geod ); /* free projection parameters */ - P->pfree(P); + P->destructor (P, 0); } } - - - - - - - - -/************************************************************************/ -/* pj_prepare() */ -/* */ -/* Helper function for the PJ_xxxx functions providing the */ -/* projection specific setup for each projection type. */ -/* */ -/* Currently not used, but placed here as part of the material */ -/* Demonstrating the idea for a future PJ_xxx architecture */ -/* (cf. pj_minimal.c) */ -/* */ -/************************************************************************/ -void pj_prepare (PJ *P, const char *description, void (*freeup)(struct PJconsts *), size_t sizeof_struct_opaque) { - P->descr = description; - P->pfree = freeup; - P->opaque = pj_calloc (1, sizeof_struct_opaque); -} diff --git a/src/pj_malloc.c b/src/pj_malloc.c index 330b14a6..52cf7deb 100644 --- a/src/pj_malloc.c +++ b/src/pj_malloc.c @@ -115,7 +115,7 @@ pointer" to signal an error in a multi level allocation: /*****************************************************************************/ -static void *pj_freeup_msg_plain (PJ *P, int errlev) { /* Destructor */ +void *pj_default_destructor (PJ *P, int errlev) { /* Destructor */ /***************************************************************************** Does memory deallocation for "plain" PJ objects, i.e. that vast majority of PJs where the opaque object does not contain any additionally @@ -123,54 +123,13 @@ static void *pj_freeup_msg_plain (PJ *P, int errlev) { /* Destructor */ ******************************************************************************/ if (0==P) return 0; - + if (0!=errlev) pj_ctx_set_errno (P->ctx, errlev); - + if (0==P->opaque) return pj_dealloc (P); pj_dealloc (P->opaque); return pj_dealloc(P); } - - -/*****************************************************************************/ -void pj_freeup_plain (PJ *P) { -/***************************************************************************** - Adapts pj_freeup_msg_plain to the format defined for the callback in - the PJ object. - - i.e. reduces most instances of projection deallocation code to: - - static void freeup (PJ *P) { - pj_freeup_plain (P); - return; - } - - rather than: - - static void *freeup_msg_add (PJ *P, int errlev) { - if (0==P) - return 0; - pj_ctx_set_errno (P->ctx, errlev); - - if (0==P->opaque) - return pj_dealloc (P); - - (* projection specific deallocation goes here *) - - pj_dealloc (P->opaque); - return pj_dealloc(P); - } - - (* Adapts pipeline_freeup to the format defined for the PJ object *) - static void freeup_msg_add (PJ *P) { - freeup_new_add (P, 0); - return; - } - - ******************************************************************************/ - pj_freeup_msg_plain (P, 0); - return; - } diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index 5c9f398b..acf0b577 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -12,7 +12,7 @@ * Author: Thomas Knudsen, thokn@sdfe.dk, 2016-06-09/2016-11-06 * ****************************************************************************** - * Copyright (c) 2016, Thomas Knudsen/SDFE + * Copyright (c) 2016, 2017 Thomas Knudsen/SDFE * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -36,7 +36,7 @@ #include #include "proj_internal.h" #include "projects.h" -#include +#include "geodesic.h" #include #include @@ -407,34 +407,20 @@ PJ *proj_destroy (PJ *P) { return 0; } -/* For now, if PJ itself is clean, we return the thread local error level. */ -/* This may change as OBS_API error reporting matures */ int proj_errno (PJ *P) { - if (0==P) - return pj_ctx_get_errno (pj_get_default_ctx ()); - if (0 != P->last_errno) - return P->last_errno; return pj_ctx_get_errno (pj_get_ctx (P)); } /*****************************************************************************/ void proj_errno_set (PJ *P, int err) { /****************************************************************************** - Sets errno in the PJ, and bubbles it up to the context and pj_errno levels - through the low level pj_ctx interface. + Sets errno at the context and bubble it up to the thread local errno ******************************************************************************/ - if (0==P) { - errno = EINVAL; - return; - } - /* Use proj_errno_reset to explicitly clear the error status */ if (0==err) return; - /* set local error level */ - P->last_errno = err; - /* and let it bubble up */ + /* For P==0 err goes to the default context */ proj_context_errno_set (pj_get_ctx (P), err); errno = err; return; @@ -454,14 +440,16 @@ void proj_errno_restore (PJ *P, int err) { See usage example under proj_errno_reset () ******************************************************************************/ + if (0==err) + return; proj_errno_set (P, err); } /*****************************************************************************/ int proj_errno_reset (PJ *P) { /****************************************************************************** - Clears errno in the PJ, and bubbles it up to the context and - pj_errno levels through the low level pj_ctx interface. + Clears errno in the context and thread local levels + through the low level pj_ctx interface. Returns the previous value of the errno, for convenient reset/restore operations: @@ -471,24 +459,17 @@ int proj_errno_reset (PJ *P) { do_something_with_P (P); - (* failure - keep latest error status *) + // failure - keep latest error status if (proj_errno(P)) return; - (* success - restore previous error status *) + // success - restore previous error status proj_errno_restore (P, last_errno); return; } ******************************************************************************/ int last_errno; - if (0==P) { - errno = EINVAL; - return EINVAL; - } last_errno = proj_errno (P); - /* set local error level */ - P->last_errno = 0; - /* and let it bubble up */ pj_ctx_set_errno (pj_get_ctx (P), 0); errno = 0; return last_errno; diff --git a/src/projects.h b/src/projects.h index 872bf816..ece88cde 100644 --- a/src/projects.h +++ b/src/projects.h @@ -253,62 +253,8 @@ struct PJconsts { void (*spc)(LP, PJ *, struct FACTORS *); - void (*pfree)(PJ *); - - /************************************************************************************* - - E R R O R R E P O R T I N G - - ************************************************************************************** - - Currently, we're doing error reporting through the context->last_errno indicator. - - It is, however, not entirely sure this will be the right way to do it in all - cases: During allocation/initialization, it is certainly nice to have a higher - level error indicator, since we primarily signal "something went wrong", by - returning 0 from the pj_init family of functions - and with a null return we - cannot pass messages through internal state in the PJ object. - - Historically, the errno variable has been used for that kind of messages, but - apparently, thread safety was added to PROJ.4 at a time where it was not clear - that errno is actually thread local. - - Additionally, errno semantics has historically been misinterpreted in parts of - pj_init.c, a misinterpretation, that was mitigated by a hack in pj_malloc.c - some 15 years ago. - - This PJ-local errno is a first step towards a more structured approach to - error reporting, being implemented in the OBS_API (cf. pj_obs_api.[ch]), and - related plumbing efforts. - - In due course this will let us get rid of the pj_malloc.c hack, and allow us - to introduce a more layered error reporting structure, where errors are - reported where they occur, and bubble up to the higher levels (context->errno, - then thread local errno), so the highest level indicate "something went wrong - somewhere", then the more localized ones can be used for pinpointing: - - errno: "something went wrong somewhere on this thread", - context->last_errno: "something went wrong in some PROJ.4 related code", - PJ->last_errno: "It was in THIS PJ something went wrong", - pj_strerrno: "This was what went wrong". - - Which will be quite helpful, once fully implemented, especially for - debugging complex transformation pipelines, while still maintaining backward - compatibility in the messaging system. - - Note that there is even a global pj_errno, which is here and there accessed - without acquiring lock. This, and the practise of resetting the thread local - errno, should be given some consideration during the cleanup of the error - reporting system. - - The name "last_errno", rather than "errno" is used partially for alignment - with the context->last_errno, partially because in a multithreaded environment, - errno is a macro, and spurious spaces turning "errno" into a separate token - will expose it to macro expansion, to the tune of much confusion and agony. - - **************************************************************************************/ - int last_errno; - + void *(*destructor)(PJ *, int); + /************************************************************************************* @@ -616,7 +562,7 @@ C_NAMESPACE PJ *pj_##name (PJ *P) { \ P = (PJ*) pj_calloc (1, sizeof(PJ)); \ if (0==P) \ return 0; \ - P->pfree = freeup; \ + P->destructor = pj_default_destructor; \ P->descr = des_##name; \ return P; \ } \ @@ -707,8 +653,6 @@ int pj_datum_set(projCtx,paralist *, PJ *); int pj_prime_meridian_set(paralist *, PJ *); int pj_angular_units_set(paralist *, PJ *); -void pj_prepare (PJ *P, const char *description, void (*freeup)(struct PJconsts *), size_t sizeof_struct_opaque); - paralist *pj_clone_paralist( const paralist* ); paralist *pj_search_initcache( const char *filekey ); void pj_insert_initcache( const char *filekey, const paralist *list); @@ -822,6 +766,8 @@ struct PJ_LIST *pj_get_list_ref( void ); struct PJ_SELFTEST_LIST *pj_get_selftest_list_ref ( void ); struct PJ_PRIME_MERIDIANS *pj_get_prime_meridians_ref( void ); +void *pj_default_destructor (PJ *P, int errlev); + double pj_atof( const char* nptr ); double pj_strtod( const char *nptr, char **endptr ); void pj_freeup_plain (PJ *P); -- cgit v1.2.3 From 0495fdca92fc620d44572ce1e4e871f57f968198 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 27 Sep 2017 14:47:07 +0200 Subject: Add PJD_ERR_* aliases for error numbers without one --- src/projects.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/projects.h b/src/projects.h index ece88cde..47f4261f 100644 --- a/src/projects.h +++ b/src/projects.h @@ -470,7 +470,24 @@ struct FACTORS { /* library errors */ #define PJD_ERR_NO_ARGS -1 +#define PJD_ERR_NO_OPTION_IN_INIT_FILE -2 +#define PJD_ERR_NO_COLOR_IN_INIT_STRING -3 +#define PJD_ERR_PROJ_NOT_NAMED -4 +#define PJD_ERR_UNKNOWN_PROJECTION_ID -5 +#define PJD_ERR_ECCENTRICITY_IS_ONE -6 +#define PJD_ERR_UNKNOW_UNIT_ID -7 +#define PJD_ERR_INVALID_BOOLEAN_PARAM -8 +#define PJD_ERR_UNKNOWN_ELLP_PARAM -9 +#define PJD_ERR_REC_FLATTENING_IS_ZERO -10 +#define PJD_ERR_REF_RAD_LARGER_THAN_90 -11 +#define PJD_ERR_ES_LESS_THAN_ZERO -12 +#define PJD_ERR_MAJOR_AXIS_NOT_GIVEN -13 #define PJD_ERR_LAT_OR_LON_EXCEED_LIMIT -14 +#define PJD_ERR_INVALID_X_OR_Y -15 +#define PJD_ERR_WRONG_FORMAT_DMS_VALUE -16 +#define PJD_ERR_NON_CONV_INV_MERI_DIST -17 +#define PJD_ERR_NON_CON_INV_PHI2 -18 +#define PJD_ERR_ACOS_ASIN_ARG_TOO_LARGE -19 #define PJD_ERR_TOLERANCE_CONDITION -20 #define PJD_ERR_CONIC_LAT_EQUAL -21 #define PJD_ERR_LAT_LARGER_THAN_90 -22 @@ -482,20 +499,27 @@ struct FACTORS { #define PJD_ERR_LSAT_NOT_IN_RANGE -28 #define PJD_ERR_PATH_NOT_IN_RANGE -29 #define PJD_ERR_H_LESS_THAN_ZERO -30 +#define PJD_ERR_K_LESS_THAN_ZERO -31 #define PJD_ERR_LAT_1_OR_2_ZERO_OR_90 -32 #define PJD_ERR_LAT_0_OR_ALPHA_EQ_90 -33 #define PJD_ERR_ELLIPSOID_USE_REQUIRED -34 #define PJD_ERR_INVALID_UTM_ZONE -35 +#define PJD_ERR_TCHEBY_VAL_OUT_OF_RANGE -36 #define PJD_ERR_FAILED_TO_FIND_PROJ -37 +#define PJD_ERR_FAILED_TO_LOAD_GRID -38 #define PJD_ERR_INVALID_M_OR_N -39 #define PJD_ERR_N_OUT_OF_RANGE -40 +#define PJD_ERR_LAT_1_2_UNSPECIFIED -41 #define PJD_ERR_ABS_LAT1_EQ_ABS_LAT2 -42 #define PJD_ERR_LAT_0_HALF_PI_FROM_MEAN -43 +#define PJD_ERR_UNPARSEABLE_CS_DEF -44 #define PJD_ERR_GEOCENTRIC -45 #define PJD_ERR_UNKNOWN_PRIME_MERIDIAN -46 #define PJD_ERR_AXIS -47 #define PJD_ERR_GRID_AREA -48 #define PJD_ERR_INVALID_SWEEP_AXIS -49 +#define PJD_ERR_MALFORMED_PIPELINE -50 +#define PJD_ERR_UNIT_FACTOR_LESS_THAN_0 -51 #define PJD_ERR_INVALID_SCALE -52 #define PJD_ERR_NON_CONVERGENT -53 #define PJD_ERR_MISSING_ARGS -54 -- cgit v1.2.3 From 33e1c8e78f7bb826617f08f29e182b530d2ea153 Mon Sep 17 00:00:00 2001 From: Thomas Knudsen Date: Thu, 28 Sep 2017 16:40:27 +0200 Subject: Introducing the cct 'Coordinate Conversion and Transformation' program (#574) * Introducing the cct 'Coordinate Conversion and Transformation' program * cct: Add some rudimentary documentation * Removed documentation again, moving to a separate doc PR * Minor corrections in response to a review by @kbevers --- src/CMakeLists.txt | 6 + src/Makefile.am | 6 +- src/bin_cct.cmake | 9 + src/cct.c | 324 +++++++++++++++++++++++++++++ src/makefile.vc | 8 +- src/optargpm.h | 593 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/proj_strtod.c | 251 +++++++++++++++++++++++ 7 files changed, 1194 insertions(+), 3 deletions(-) create mode 100644 src/bin_cct.cmake create mode 100644 src/cct.c create mode 100644 src/optargpm.h create mode 100644 src/proj_strtod.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eec7ddec..788273a9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ include(lib_proj.cmake) # configure executable build +option(BUILD_CCT "Build cct (coordinate conversion and transformation tool)" ON) option(BUILD_CS2CS "Build cs2cs (coordinate systems to coordinate systems translation tool)" ON) option(BUILD_PROJ "Build proj (cartographic projection tool : latlong <-> projected coordinates" ON) option(BUILD_GEOD "Build geod (computation of geodesic lines)" ON) @@ -22,6 +23,11 @@ if(NOT MSVC) endif () endif () +if(BUILD_CCT) + include(bin_cct.cmake) + set(BIN_TARGETS ${BIN_TARGETS} cct) +endif(BUILD_CCT) + if(BUILD_CS2CS) include(bin_cs2cs.cmake) set(BIN_TARGETS ${BIN_TARGETS} cs2cs) diff --git a/src/Makefile.am b/src/Makefile.am index 12d11c5f..de8fff4b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = @C_WFLAGS@ -bin_PROGRAMS = proj nad2bin geod cs2cs +bin_PROGRAMS = proj nad2bin geod cs2cs cct EXTRA_PROGRAMS = multistresstest test228 TESTS = geodtest @@ -12,12 +12,13 @@ AM_CPPFLAGS = -DPROJ_LIB=\"$(pkgdatadir)\" \ include_HEADERS = proj.h proj_api.h projects.h geodesic.h \ org_proj4_Projections.h org_proj4_PJ.h -EXTRA_DIST = makefile.vc proj.def bin_cs2cs.cmake \ +EXTRA_DIST = makefile.vc proj.def bin_cct.cmake bin_cs2cs.cmake \ bin_geod.cmake bin_nad2bin.cmake bin_proj.cmake \ lib_proj.cmake CMakeLists.txt bin_geodtest.cmake geodtest.c proj_SOURCES = proj.c gen_cheb.c p_series.c cs2cs_SOURCES = cs2cs.c gen_cheb.c p_series.c +cct_SOURCES = cct.c proj_strtod.c optargpm.h nad2bin_SOURCES = nad2bin.c geod_SOURCES = geod.c geod_set.c geod_interface.c geod_interface.h multistresstest_SOURCES = multistresstest.c @@ -26,6 +27,7 @@ geodtest_SOURCES = geodtest.c proj_LDADD = libproj.la cs2cs_LDADD = libproj.la +cct_LDADD = libproj.la nad2bin_LDADD = libproj.la geod_LDADD = libproj.la multistresstest_LDADD = libproj.la @THREAD_LIB@ diff --git a/src/bin_cct.cmake b/src/bin_cct.cmake new file mode 100644 index 00000000..a204e7e7 --- /dev/null +++ b/src/bin_cct.cmake @@ -0,0 +1,9 @@ +set(CCT_SRC cct.c proj_strtod.c) +set(CCT_INCLUDE optargpm.h) + +source_group("Source Files\\Bin" FILES ${CCT_SRC}) + +add_executable(cct ${CCT_SRC} ${CCT_INCLUDE}) +target_link_libraries(cct ${PROJ_LIBRARIES}) +install(TARGETS cct + RUNTIME DESTINATION ${BINDIR}) diff --git a/src/cct.c b/src/cct.c new file mode 100644 index 00000000..83a0b0a3 --- /dev/null +++ b/src/cct.c @@ -0,0 +1,324 @@ +/*********************************************************************** + + The cct 4D Transformation program + +************************************************************************ + +cct is a 4D equivalent to the "proj" projection program. + +cct is an acronym meaning "Coordinate Conversion and Transformation". + +The acronym refers to definitions given in the OGC 08-015r2/ISO-19111 +standard "Geographical Information -- Spatial Referencing by Coordinates", +which defines two different classes of coordinate operations: + +*Coordinate Conversions*, which are coordinate operations where input +and output datum are identical (e.g. conversion from geographical to +cartesian coordinates) and + +*Coordinate Transformations*, which are coordinate operations where +input and output datums differ (e.g. change of reference frame). + +cct, however, also refers to Carl Christian Tscherning (1942--2014), +professor of Geodesy at the University of Copenhagen, mentor and advisor +for a generation of Danish geodesists, colleague and collaborator for +two generations of global geodesists, Secretary General for the +International Association of Geodesy, IAG (1995--2007), fellow of the +Amercan Geophysical Union (1991), recipient of the IAG Levallois Medal +(2007), the European Geosciences Union Vening Meinesz Medal (2008), and +of numerous other honours. + +cct, or Christian, as he was known to most of us, was recognized for his +good mood, his sharp wit, his tireless work, and his great commitment to +the development of geodesy - both through his scientific contributions, +comprising more than 250 publications, and by his mentoring and teaching +of the next generations of geodesists. + +As Christian was an avid Fortran programmer, and a keen Unix connoiseur, +he would have enjoyed to know that his initials would be used to name a +modest Unix style transformation filter, hinting at the tireless aspect +of his personality, which was certainly one of the reasons he accomplished +so much, and meant so much to so many people. + +Hence, in honour of cct (the geodesist) this is cct (the program). + +************************************************************************ + +Thomas Knudsen, thokn@sdfe.dk, 2016-05-25/2017-09-19 + +************************************************************************ + +* Copyright (c) 2016, 2017 Thomas Knudsen +* Copyright (c) 2017, SDFE +* +* 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 "optargpm.h" +#include +#include +#include +#include +#include +#include +#include + +double proj_strtod(const char *str, char **endptr); +double proj_atof(const char *str); + +char *column (char *buf, int n); +PJ_COORD parse_input_line (char *buf, int *columns, double fixed_height, double fixed_time); +int print_output_line (FILE *fout, char *buf, PJ_COORD point); +int main(int argc, char **argv); + + + +static const char usage[] = { + "--------------------------------------------------------------------------------\n" + "Usage: %s [-options]... [+operator_specs]... infile...\n" + "--------------------------------------------------------------------------------\n" + "Options:\n" + "--------------------------------------------------------------------------------\n" + " -o /path/to/file Specify output file name\n" + " -c x,y,z,t Specify input columns for (up to) 4 input parameters.\n" + " Defaults to 1,2,3,4\n" + " -z value Provide a fixed z value for all input data (e.g. -z 0)\n" + " -t value Provide a fixed t value for all input data (e.g. -t 0)\n" + " -v Verbose: Provide non-essential informational output.\n" + " Repeat -v for more verbosity (e.g. -vv)\n" + "--------------------------------------------------------------------------------\n" + "Long Options:\n" + "--------------------------------------------------------------------------------\n" + " --output Alias for -o\n" + " --columns Alias for -c\n" + " --height Alias for -z\n" + " --time Alias for -t\n" + " --verbose Alias for -v\n" + " --help Alias for -h\n" + "--------------------------------------------------------------------------------\n" + "Operator Specs:\n" + "--------------------------------------------------------------------------------\n" + "The operator specs describe the action to be performed by cct, e.g:\n" + "\n" + " +proj=utm +ellps=GRS80 +zone=32\n" + "\n" + "instructs cct to convert input data to Universal Transverse Mercator, zone 32\n" + "coordinates, based on the GRS80 ellipsoid.\n" + "\n" + "Hence, the command\n" + "\n" + " echo 12 55 | cct -z0 -t0 +proj=utm +zone=32 +ellps=GRS80\n" + "\n" + "Should give results comparable to the classic proj command\n" + "\n" + " echo 12 55 | proj +proj=utm +zone=32 +ellps=GRS80\n" + "--------------------------------------------------------------------------------\n" + "Examples:\n" + "--------------------------------------------------------------------------------\n" + "1. convert geographical input to UTM zone 32 on the GRS80 ellipsoid:\n" + " cct +proj=utm +ellps=GRS80 +zone=32\n" + "2. roundtrip accuracy check for the case above:\n" + " cct +proj=pipeline +proj=utm +ellps=GRS80 +zone=32 +step +step +inv\n" + "3. as (1) but specify input columns for longitude, latitude, height and time:\n" + " cct -c 5,2,1,4 +proj=utm +ellps=GRS80 +zone=32\n" + "4. as (1) but specify fixed height and time, hence needing only 2 cols in input:\n" + " cct -t 0 -z 0 +proj=utm +ellps=GRS80 +zone=32\n" + "--------------------------------------------------------------------------------\n" +}; + +int main(int argc, char **argv) { + PJ *P; + PJ_COORD point; + OPTARGS *o; + FILE *fout = stdout; + char *buf; + int input_unit, output_unit, nfields = 4, direction = 1, verbose; + double fixed_z = HUGE_VAL, fixed_time = HUGE_VAL; + int columns_xyzt[] = {1, 2, 3, 4}; + const char *longflags[] = {"v=verbose", "h=help", 0}; + const char *longkeys[] = {"o=output", "c=columns", "z=height", "t=time", 0}; + + o = opt_parse (argc, argv, "hv", "cozt", longflags, longkeys); + if (0==o) + return 0; + + if (opt_given (o, "h")) { + printf (usage, o->progname); + return 0; + } + + + direction = opt_given (o, "I")? -1: 1; + verbose = opt_given (o, "v"); + + if (opt_given (o, "o")) + fout = fopen (opt_arg (o, "output"), "rt"); + if (0==fout) { + fprintf (stderr, "%s: Cannot open '%s' for output\n", o->progname, opt_arg (o, "output")); + free (o); + return 1; + } + if (verbose > 3) + fprintf (fout, "%s: Running in very verbose mode\n", o->progname); + + + + if (opt_given (o, "z")) { + fixed_z = proj_atof (opt_arg (o, "z")); + nfields--; + } + + if (opt_given (o, "t")) { + fixed_time = proj_atof (opt_arg (o, "t")); + nfields--; + } + + if (opt_given (o, "c")) { + int ncols = sscanf (opt_arg (o, "c"), "%d,%d,%d,%d", columns_xyzt, columns_xyzt+1, columns_xyzt+3, columns_xyzt+3); + if (ncols != nfields) { + fprintf (stderr, "%s: Too few input columns given: '%s'\n", o->progname, opt_arg (o, "c")); + free (o); + if (stdout != fout) + fclose (fout); + return 1; + } + } + + /* Setup transformation */ + P = proj_create_argv (0, o->pargc, o->pargv); + if ((0==P) || (0==o->pargc)) { + fprintf (stderr, "%s: Bad transformation arguments. '%s -h' for help\n", o->progname, o->progname); + free (o); + if (stdout != fout) + fclose (fout); + return 1; + } + + input_unit = P->left; + output_unit = P->right; + if (PJ_IO_UNITS_CLASSIC==P->left) + input_unit = PJ_IO_UNITS_RADIANS; + if (PJ_IO_UNITS_CLASSIC==P->right) + output_unit = PJ_IO_UNITS_METERS; + if (direction==-1) { + enum pj_io_units swap = input_unit; + input_unit = output_unit; + output_unit = swap; + } + + /* Allocate input buffer */ + buf = calloc (1, 10000); + if (0==buf) { + fprintf (stderr, "%s: Out of memory\n", o->progname); + pj_free (P); + free (o); + if (stdout != fout) + fclose (fout); + return 1; + } + + + /* Loop over all lines of all input files */ + while (opt_input_loop (o, optargs_file_format_text)) { + void *ret = fgets (buf, 10000, o->input); + int res; + opt_eof_handler (o); + if (0==ret) { + fprintf (stderr, "Read error in record %d\n", (int) o->record_index); + continue; + } + point = parse_input_line (buf, columns_xyzt, fixed_z, fixed_time); + if (PJ_IO_UNITS_RADIANS==input_unit) { + point.lpzt.lam = proj_torad (point.lpzt.lam); + point.lpzt.phi = proj_torad (point.lpzt.phi); + } + point = proj_trans_coord (P, direction, point); + if (PJ_IO_UNITS_RADIANS==output_unit) { + point.lpzt.lam = proj_todeg (point.lpzt.lam); + point.lpzt.phi = proj_todeg (point.lpzt.phi); + } + res = print_output_line (fout, buf, point); + if (0==res) { + fprintf (fout, "# UNREADABLE: %s", buf); + if (verbose) + fprintf (stderr, "%s: Could not parse file '%s' line %d\n", o->progname, opt_filename (o), opt_record (o)); + } + } + if (stdout != fout) + fclose (fout); + free (o); + return 0; +} + + + + + +/* return a pointer to the n'th column of buf */ +char *column (char *buf, int n) { + int i; + if (n <= 0) + return buf; + for (i = 0; i < n; i++) { + while (isspace(*buf)) + buf++; + if (i == n - 1) + break; + while ((0 != *buf) && !isspace(*buf)) + buf++; + } + return buf; +} + + +PJ_COORD parse_input_line (char *buf, int *columns, double fixed_height, double fixed_time) { + PJ_COORD err = proj_coord (HUGE_VAL, HUGE_VAL, HUGE_VAL, HUGE_VAL); + PJ_COORD result = err; + int prev_errno = errno; + char *endptr = 0; + errno = 0; + + result.xyzt.z = fixed_height; + result.xyzt.t = fixed_time; + result.xyzt.x = proj_strtod (column (buf, columns[0]), &endptr); + result.xyzt.y = proj_strtod (column (buf, columns[1]), &endptr); + if (result.xyzt.z==HUGE_VAL) + result.xyzt.z = proj_strtod (column (buf, columns[2]), &endptr); + if (result.xyzt.t==HUGE_VAL) + result.xyzt.t = proj_strtod (column (buf, columns[3]), &endptr); + + if (0!=errno) + return err; + + errno = prev_errno; + return result; +} + + +int print_output_line (FILE *fout, char *buf, PJ_COORD point) { + char *c; + if (HUGE_VAL!=point.xyzt.x) + return fprintf (fout, "%20.15f %20.15f %20.15f %20.15f\n", point.xyzt.x, point.xyzt.y, point.xyzt.z, point.xyzt.t); + c = column (buf, 1); + /* reflect comments and blanks */ + if (c && ((*c=='\0') || (*c=='#'))) + return fprintf (fout, "%s\n", buf); + return 0; +} diff --git a/src/makefile.vc b/src/makefile.vc index cc57d806..7ab0dfc7 100644 --- a/src/makefile.vc +++ b/src/makefile.vc @@ -70,11 +70,13 @@ LIBOBJ = $(support) $(pseudo) $(azimuthal) $(conic) $(cylinder) $(misc) \ PROJEXE_OBJ = proj.obj gen_cheb.obj p_series.obj emess.obj CS2CSEXE_OBJ = cs2cs.obj gen_cheb.obj p_series.obj emess.obj GEODEXE_OBJ = geod.obj geod_set.obj geod_interface.obj emess.obj +CCTEXE_OBJ = cct.obj proj_strtod.obj MULTISTRESSTEST_OBJ = multistresstest.obj PROJ_DLL = proj$(VERSION).dll PROJ_EXE = proj.exe CS2CS_EXE = cs2cs.exe GEOD_EXE = geod.exe +CCT_EXE = cct.exe NAD2BIN_EXE = nad2bin.exe MULTISTRESSTEST_EXE = multistresstest.exe @@ -83,7 +85,7 @@ CFLAGS = /nologo -I. -DPROJ_LIB=\"$(PROJ_LIB_DIR)\" \ default: all -all: proj.lib $(PROJ_EXE) $(CS2CS_EXE) $(GEOD_EXE) $(NAD2BIN_EXE) +all: proj.lib $(PROJ_EXE) $(CS2CS_EXE) $(GEOD_EXE) $(CCT_EXE) $(NAD2BIN_EXE) proj.lib: $(LIBOBJ) if exist proj.lib del proj.lib @@ -108,6 +110,10 @@ $(GEOD_EXE): $(GEODEXE_OBJ) $(EXE_PROJ) cl $(GEODEXE_OBJ) $(EXE_PROJ) if exist $(GEOD_EXE).manifest mt -manifest $(GEOD_EXE).manifest -outputresource:$(GEOD_EXE);1 +$(CCT_EXE): $(CCTEXE_OBJ) $(EXE_PROJ) + cl $(CCTEXE_OBJ) $(EXE_PROJ) + if exist $(CCT_EXE).manifest mt -manifest $(CCT_EXE).manifest -outputresource:$(CCT_EXE);1 + $(NAD2BIN_EXE): nad2bin.obj emess.obj $(EXE_PROJ) cl nad2bin.obj emess.obj $(EXE_PROJ) diff --git a/src/optargpm.h b/src/optargpm.h new file mode 100644 index 00000000..6be2c9ef --- /dev/null +++ b/src/optargpm.h @@ -0,0 +1,593 @@ +/*********************************************************************** + + OPTARGPM - a header-only library for decoding + PROJ.4 style command line options + + Thomas Knudsen, 2017-09-10 + +************************************************************************ + +For PROJ.4 command line programs, we have a somewhat complex option +decoding situation, since we have to navigate in a cocktail of classic +single letter style options, prefixed by "-", GNU style long options +prefixwd by "--", transformation specification elements prefixed by "+", +and input file names prefixed by "" nothing. + +Hence, classic getopt.h style decoding does not cut the mustard, so +this is an attempt to catch up and chop the ketchup. + +Since optargpm (for "optarg plus minus") does not belong, in any +obvious way, in any systems development library, it is provided as +a "header only" library. + +While this is conventional in C++, it is frowned at in plain C. +But frown away - "header only" has its places, and this is one of +them. + +By convention, we expect a command line to consist of the following +elements: + + + [short ("-")/long ("--") options} + [operator ("+") specs] + [operands/input files] + +or less verbose: + + [options] [operator specs] [operands] + +or less abstract: + + proj -I --output=foo +proj=utm +zone=32 +ellps=GRS80 bar baz... + +Where + +Operator is proj +Options are -I --output=foo +Operator specs are +proj=utm +zone=32 +ellps=GRS80 +Operands are bar baz + + +While claiming neither to save the world, nor to hint at the "shape of +jazz to come", at least optargpm has shown useful in constructing cs2cs +style transformation filters. + +Supporting a wide range of option syntax, the getoptpm API is somewhat +quirky, but also compact, consisting of one data type, 3(+2) functions, +and one enumeration: + +OPTARGS + Housekeeping data type. An instance of OPTARGS is conventionally + called o or opt +opt_parse (opt, argc, argv ...): + The work horse: Define supported options; Split (argc, argv) + into groups (options, op specs, operands); Parse option + arguments. +opt_given (o, option): + The number of times