PostGIS  3.7.0dev-r@@SVN_REVISION@@
lwutil.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright (C) 2004-2015 Sandro Santilli <strk@kbt.io>
22  * Copyright (C) 2006 Mark Leslie <mark.leslie@lisasoft.com>
23  * Copyright (C) 2008-2009 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
24  * Copyright (C) 2009-2015 Paul Ramsey <pramsey@cleverelephant.ca>
25  * Copyright (C) 2010 Olivier Courtin <olivier.courtin@camptocamp.com>
26  *
27  **********************************************************************/
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <ctype.h> /* for tolower */
34 
35 /* Global variables */
36 #include "../postgis_config.h"
37 #include "liblwgeom_internal.h"
38 #include "lwgeom_log.h"
39 
40 /* Default allocators */
41 static void * default_allocator(size_t size);
42 static void default_freeor(void *mem);
43 static void * default_reallocator(void *mem, size_t size);
47 
48 /* Default reporters */
49 static void default_noticereporter(const char *fmt, va_list ap) __attribute__ ((format (printf, 1, 0)));
50 static void default_errorreporter(const char *fmt, va_list ap) __attribute__ ((format (printf, 1, 0)));
53 
54 /* Default logger */
55 static void default_debuglogger(int level, const char *fmt, va_list ap) __attribute__ ((format (printf, 2, 0)));
57 
58 #define LW_MSG_MAXLEN 256
59 
60 static char *lwgeomTypeName[] =
61 {
62  "Unknown",
63  "Point",
64  "LineString",
65  "Polygon",
66  "MultiPoint",
67  "MultiLineString",
68  "MultiPolygon",
69  "GeometryCollection",
70  "CircularString",
71  "CompoundCurve",
72  "CurvePolygon",
73  "MultiCurve",
74  "MultiSurface",
75  "PolyhedralSurface",
76  "Triangle",
77  "Tin"
78 };
79 
80 /*
81  * Default allocators
82  *
83  * We include some default allocators that use malloc/free/realloc
84  * along with stdout/stderr since this is the most common use case
85  *
86  */
87 
88 static void *
89 default_allocator(size_t size)
90 {
91  void *mem = malloc(size);
92  return mem;
93 }
94 
95 static void
96 default_freeor(void *mem)
97 {
98  free(mem);
99 }
100 
101 static void *
102 default_reallocator(void *mem, size_t size)
103 {
104  void *ret = realloc(mem, size);
105  return ret;
106 }
107 
108 /*
109  * Default lwnotice/lwerror handlers
110  *
111  * Since variadic functions cannot pass their parameters directly, we need
112  * wrappers for these functions to convert the arguments into a va_list
113  * structure.
114  */
115 
116 static void
117 default_noticereporter(const char *fmt, va_list ap)
118 {
119  char msg[LW_MSG_MAXLEN+1];
120  vsnprintf (msg, LW_MSG_MAXLEN, fmt, ap);
121  msg[LW_MSG_MAXLEN]='\0';
122  fprintf(stderr, "%s\n", msg);
123 }
124 
125 static void
126 default_debuglogger(int level, const char *fmt, va_list ap)
127 {
128  char msg[LW_MSG_MAXLEN+1];
129  if ( POSTGIS_DEBUG_LEVEL >= level )
130  {
131  /* Space pad the debug output */
132  int i;
133  for ( i = 0; i < level; i++ )
134  msg[i] = ' ';
135  vsnprintf(msg+i, LW_MSG_MAXLEN-i, fmt, ap);
136  msg[LW_MSG_MAXLEN]='\0';
137  fprintf(stderr, "%s\n", msg);
138  }
139 }
140 
141 static void
142 default_errorreporter(const char *fmt, va_list ap)
143 {
144  char msg[LW_MSG_MAXLEN+1];
145  vsnprintf (msg, LW_MSG_MAXLEN, fmt, ap);
146  msg[LW_MSG_MAXLEN]='\0';
147  fprintf(stderr, "%s\n", msg);
148  exit(1);
149 }
150 
157 void
159  lwfreeor freeor, lwreporter errorreporter,
160  lwreporter noticereporter) {
161 
162  if ( allocator ) lwalloc_var = allocator;
163  if ( reallocator ) lwrealloc_var = reallocator;
164  if ( freeor ) lwfree_var = freeor;
165 
166  if ( errorreporter ) lwerror_var = errorreporter;
167  if ( noticereporter ) lwnotice_var = noticereporter;
168 }
169 
170 void
172 
173  if ( debuglogger ) lwdebug_var = debuglogger;
174 }
175 
176 void
177 lwnotice(const char *fmt, ...)
178 {
179  va_list ap;
180 
181  va_start(ap, fmt);
182 
183  /* Call the supplied function */
184  (*lwnotice_var)(fmt, ap);
185 
186  va_end(ap);
187 }
188 
189 void
190 lwerror(const char *fmt, ...)
191 {
192  va_list ap;
193 
194  va_start(ap, fmt);
195 
196  /* Call the supplied function */
197  (*lwerror_var)(fmt, ap);
198 
199  va_end(ap);
200 }
201 
202 void
203 lwdebug(int level, const char *fmt, ...)
204 {
205  va_list ap;
206 
207  va_start(ap, fmt);
208 
209  /* Call the supplied function */
210  (*lwdebug_var)(level, fmt, ap);
211 
212  va_end(ap);
213 }
214 
215 const char*
217 {
218  if ( type > 15 )
219  {
220  /* assert(0); */
221  return "Invalid type";
222  }
223  return lwgeomTypeName[(int ) type];
224 }
225 
226 void *
227 lwalloc(size_t size)
228 {
229  void *mem = lwalloc_var(size);
230  return mem;
231 }
232 
233 void *
234 lwalloc0(size_t size)
235 {
236  void *mem = lwalloc_var(size);
237  memset(mem, 0, size);
238  return mem;
239 }
240 
241 void *
242 lwrealloc(void *mem, size_t size)
243 {
244  return lwrealloc_var(mem, size);
245 }
246 
247 void
248 lwfree(void *mem)
249 {
250  lwfree_var(mem);
251 }
252 
253 char *
254 lwstrdup(const char* a)
255 {
256  size_t l = strlen(a)+1;
257  char *b = lwalloc(l);
258  strncpy(b, a, l);
259  return b;
260 }
261 
262 /*
263  * Returns a new string which contains a maximum of maxlength characters starting
264  * from startpos and finishing at endpos (0-based indexing). If the string is
265  * truncated then the first or last characters are replaced by "..." as
266  * appropriate.
267  *
268  * The caller should specify start or end truncation by setting the truncdirection
269  * parameter as follows:
270  * 0 - start truncation (i.e. characters are removed from the beginning)
271  * 1 - end truncation (i.e. characters are removed from the end)
272  */
273 
274 char *lwmessage_truncate(char *str, int startpos, int endpos, int maxlength, int truncdirection)
275 {
276  char *output;
277  char *outstart;
278 
279  /* Allocate space for new string */
280  output = lwalloc(maxlength + 4);
281  output[0] = '\0';
282 
283  /* Start truncation */
284  if (truncdirection == 0)
285  {
286  /* Calculate the start position */
287  if (endpos - startpos < maxlength)
288  {
289  outstart = str + startpos;
290  strncat(output, outstart, endpos - startpos + 1);
291  }
292  else
293  {
294  if (maxlength >= 3)
295  {
296  /* Add "..." prefix */
297  outstart = str + endpos + 1 - maxlength + 3;
298  strncat(output, "...", 4);
299  strncat(output, outstart, maxlength - 3);
300  }
301  else
302  {
303  /* maxlength is too small; just output "..." */
304  strncat(output, "...", 4);
305  }
306  }
307  }
308 
309  /* End truncation */
310  if (truncdirection == 1)
311  {
312  /* Calculate the end position */
313  if (endpos - startpos < maxlength)
314  {
315  outstart = str + startpos;
316  strncat(output, outstart, endpos - startpos + 1);
317  }
318  else
319  {
320  if (maxlength >= 3)
321  {
322  /* Add "..." suffix */
323  outstart = str + startpos;
324  strncat(output, outstart, maxlength - 3);
325  strncat(output, "...", 4);
326  }
327  else
328  {
329  /* maxlength is too small; just output "..." */
330  strncat(output, "...", 4);
331  }
332  }
333  }
334 
335  return output;
336 }
337 
338 int32_t
339 clamp_srid(int32_t srid)
340 {
341  int newsrid = srid;
342 
343  if ( newsrid <= 0 ) {
344  if ( newsrid != SRID_UNKNOWN ) {
345  newsrid = SRID_UNKNOWN;
346  lwnotice("SRID value %d converted to the officially unknown SRID value %d", srid, newsrid);
347  }
348  } else if ( srid > SRID_MAXIMUM ) {
349  newsrid = SRID_USER_MAXIMUM + 1 +
350  /* -1 is to reduce likelihood of clashes */
351  /* NOTE: must match implementation in postgis_restore.pl */
352  ( srid % ( SRID_MAXIMUM - SRID_USER_MAXIMUM - 1 ) );
353  lwnotice("SRID value %d > SRID_MAXIMUM converted to %d", srid, newsrid);
354  }
355 
356  return newsrid;
357 }
358 
359 
360 
361 
362 /* Structure for the type array */
364 {
365  char *typename;
366  int type;
367  int z;
368  int m;
369 };
370 
371 /* Type array. Note that the order of this array is important in
372  that any typename in the list must *NOT* occur within an entry
373  before it. Otherwise if we search for "POINT" at the top of the
374  list we would also match MULTIPOINT, for example. */
375 
377 {
378  { "GEOMETRYCOLLECTIONZM", COLLECTIONTYPE, 1, 1 },
379  { "GEOMETRYCOLLECTIONZ", COLLECTIONTYPE, 1, 0 },
380  { "GEOMETRYCOLLECTIONM", COLLECTIONTYPE, 0, 1 },
381  { "GEOMETRYCOLLECTION", COLLECTIONTYPE, 0, 0 },
382 
383  { "GEOMETRYZM", 0, 1, 1 },
384  { "GEOMETRYZ", 0, 1, 0 },
385  { "GEOMETRYM", 0, 0, 1 },
386  { "GEOMETRY", 0, 0, 0 },
387 
388  { "POLYHEDRALSURFACEZM", POLYHEDRALSURFACETYPE, 1, 1 },
389  { "POLYHEDRALSURFACEZ", POLYHEDRALSURFACETYPE, 1, 0 },
390  { "POLYHEDRALSURFACEM", POLYHEDRALSURFACETYPE, 0, 1 },
391  { "POLYHEDRALSURFACE", POLYHEDRALSURFACETYPE, 0, 0 },
392 
393  { "TINZM", TINTYPE, 1, 1 },
394  { "TINZ", TINTYPE, 1, 0 },
395  { "TINM", TINTYPE, 0, 1 },
396  { "TIN", TINTYPE, 0, 0 },
397 
398  { "CIRCULARSTRINGZM", CIRCSTRINGTYPE, 1, 1 },
399  { "CIRCULARSTRINGZ", CIRCSTRINGTYPE, 1, 0 },
400  { "CIRCULARSTRINGM", CIRCSTRINGTYPE, 0, 1 },
401  { "CIRCULARSTRING", CIRCSTRINGTYPE, 0, 0 },
402 
403  { "COMPOUNDCURVEZM", COMPOUNDTYPE, 1, 1 },
404  { "COMPOUNDCURVEZ", COMPOUNDTYPE, 1, 0 },
405  { "COMPOUNDCURVEM", COMPOUNDTYPE, 0, 1 },
406  { "COMPOUNDCURVE", COMPOUNDTYPE, 0, 0 },
407 
408  { "CURVEPOLYGONZM", CURVEPOLYTYPE, 1, 1 },
409  { "CURVEPOLYGONZ", CURVEPOLYTYPE, 1, 0 },
410  { "CURVEPOLYGONM", CURVEPOLYTYPE, 0, 1 },
411  { "CURVEPOLYGON", CURVEPOLYTYPE, 0, 0 },
412 
413  { "MULTICURVEZM", MULTICURVETYPE, 1, 1 },
414  { "MULTICURVEZ", MULTICURVETYPE, 1, 0 },
415  { "MULTICURVEM", MULTICURVETYPE, 0, 1 },
416  { "MULTICURVE", MULTICURVETYPE, 0, 0 },
417 
418  { "MULTISURFACEZM", MULTISURFACETYPE, 1, 1 },
419  { "MULTISURFACEZ", MULTISURFACETYPE, 1, 0 },
420  { "MULTISURFACEM", MULTISURFACETYPE, 0, 1 },
421  { "MULTISURFACE", MULTISURFACETYPE, 0, 0 },
422 
423  { "MULTILINESTRINGZM", MULTILINETYPE, 1, 1 },
424  { "MULTILINESTRINGZ", MULTILINETYPE, 1, 0 },
425  { "MULTILINESTRINGM", MULTILINETYPE, 0, 1 },
426  { "MULTILINESTRING", MULTILINETYPE, 0, 0 },
427 
428  { "MULTIPOLYGONZM", MULTIPOLYGONTYPE, 1, 1 },
429  { "MULTIPOLYGONZ", MULTIPOLYGONTYPE, 1, 0 },
430  { "MULTIPOLYGONM", MULTIPOLYGONTYPE, 0, 1 },
431  { "MULTIPOLYGON", MULTIPOLYGONTYPE, 0, 0 },
432 
433  { "MULTIPOINTZM", MULTIPOINTTYPE, 1, 1 },
434  { "MULTIPOINTZ", MULTIPOINTTYPE, 1, 0 },
435  { "MULTIPOINTM", MULTIPOINTTYPE, 0, 1 },
436  { "MULTIPOINT", MULTIPOINTTYPE, 0, 0 },
437 
438  { "LINESTRINGZM", LINETYPE, 1, 1 },
439  { "LINESTRINGZ", LINETYPE, 1, 0 },
440  { "LINESTRINGM", LINETYPE, 0, 1 },
441  { "LINESTRING", LINETYPE, 0, 0 },
442 
443  { "TRIANGLEZM", TRIANGLETYPE, 1, 1 },
444  { "TRIANGLEZ", TRIANGLETYPE, 1, 0 },
445  { "TRIANGLEM", TRIANGLETYPE, 0, 1 },
446  { "TRIANGLE", TRIANGLETYPE, 0, 0 },
447 
448  { "POLYGONZM", POLYGONTYPE, 1, 1 },
449  { "POLYGONZ", POLYGONTYPE, 1, 0 },
450  { "POLYGONM", POLYGONTYPE, 0, 1 },
451  { "POLYGON", POLYGONTYPE, 0, 0 },
452 
453  { "POINTZM", POINTTYPE, 1, 1 },
454  { "POINTZ", POINTTYPE, 1, 0 },
455  { "POINTM", POINTTYPE, 0, 1 },
456  { "POINT", POINTTYPE, 0, 0 }
457 
458 };
459 #define GEOMTYPE_STRUCT_ARRAY_LEN (sizeof geomtype_struct_array/sizeof(struct geomtype_struct))
460 
461 /*
462 * We use a very simple upper case mapper here, because the system toupper() function
463 * is locale dependent and may have trouble mapping lower case strings to the upper
464 * case ones we expect (see, the "Turkisk I", http://www.i18nguy.com/unicode/turkish-i18n.html)
465 * We could also count on PgSQL sending us *lower* case inputs, as it seems to do that
466 * regardless of the case the user provides for the type arguments.
467 */
468 const char dumb_upper_map[128] = "................................................0123456789.......ABCDEFGHIJKLMNOPQRSTUVWXYZ......ABCDEFGHIJKLMNOPQRSTUVWXYZ.....";
469 
470 static char dumb_toupper(int in)
471 {
472  if ( in < 0 || in > 127 )
473  return '.';
474  return dumb_upper_map[in];
475 }
476 
477 lwflags_t lwflags(int hasz, int hasm, int geodetic)
478 {
479  lwflags_t flags = 0;
480  if (hasz)
481  FLAGS_SET_Z(flags, 1);
482  if (hasm)
483  FLAGS_SET_M(flags, 1);
484  if (geodetic)
485  FLAGS_SET_GEODETIC(flags, 1);
486  return flags;
487 }
488 
495 int geometry_type_from_string(const char *str, uint8_t *type, int *z, int *m)
496 {
497  char *tmpstr;
498  size_t tmpstartpos, tmpendpos;
499  size_t i;
500 
501  assert(str);
502  assert(type);
503  assert(z);
504  assert(m);
505 
506  /* Initialize. */
507  *type = 0;
508  *z = 0;
509  *m = 0;
510 
511  /* Locate any leading/trailing spaces */
512  tmpstartpos = 0;
513  for (i = 0; i < strlen(str); i++)
514  {
515  if (str[i] != ' ')
516  {
517  tmpstartpos = i;
518  break;
519  }
520  }
521 
522  tmpendpos = strlen(str) - 1;
523  for (i = strlen(str) - 1; i != 0; i--)
524  {
525  if (str[i] != ' ')
526  {
527  tmpendpos = i;
528  break;
529  }
530  }
531 
532  /* Copy and convert to upper case for comparison */
533  tmpstr = lwalloc(tmpendpos - tmpstartpos + 2);
534  for (i = tmpstartpos; i <= tmpendpos; i++)
535  tmpstr[i - tmpstartpos] = dumb_toupper(str[i]);
536 
537  /* Add NULL to terminate */
538  tmpstr[i - tmpstartpos] = '\0';
539 
540  /* Now check for the type */
541  for (i = 0; i < GEOMTYPE_STRUCT_ARRAY_LEN; i++)
542  {
543  if (!strcmp(tmpstr, geomtype_struct_array[i].typename))
544  {
546  *z = geomtype_struct_array[i].z;
547  *m = geomtype_struct_array[i].m;
548 
549  lwfree(tmpstr);
550 
551  return LW_SUCCESS;
552  }
553 
554  }
555 
556  lwfree(tmpstr);
557 
558  return LW_FAILURE;
559 }
560 
561 
562 
563 
564 
565 
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
#define COMPOUNDTYPE
Definition: liblwgeom.h:110
void(*) typedef void(* lwdebuglogger)(int level, const char *fmt, va_list ap) __attribute__((format(printf
Definition: liblwgeom.h:247
#define LW_FAILURE
Definition: liblwgeom.h:96
#define CURVEPOLYTYPE
Definition: liblwgeom.h:111
#define MULTILINETYPE
Definition: liblwgeom.h:106
void(* lwfreeor)(void *mem)
Definition: liblwgeom.h:244
#define SRID_USER_MAXIMUM
Maximum valid SRID value for the user We reserve 1000 values for internal use.
Definition: liblwgeom.h:212
#define MULTISURFACETYPE
Definition: liblwgeom.h:113
#define LINETYPE
Definition: liblwgeom.h:103
#define LW_SUCCESS
Definition: liblwgeom.h:97
uint16_t lwflags_t
Definition: liblwgeom.h:299
#define MULTIPOINTTYPE
Definition: liblwgeom.h:105
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:102
#define SRID_MAXIMUM
Maximum allowed SRID value in serialized geometry.
Definition: liblwgeom.h:206
void(* lwreporter)(const char *fmt, va_list ap) __attribute__((format(printf
Definition: liblwgeom.h:245
#define TINTYPE
Definition: liblwgeom.h:116
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:107
#define POLYGONTYPE
Definition: liblwgeom.h:104
#define __attribute__(x)
Definition: liblwgeom.h:228
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:114
void *(* lwreallocator)(void *mem, size_t size)
Definition: liblwgeom.h:243
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:109
void *(* lwallocator)(size_t size)
Global functions for memory/logging handlers.
Definition: liblwgeom.h:242
#define MULTICURVETYPE
Definition: liblwgeom.h:112
#define TRIANGLETYPE
Definition: liblwgeom.h:115
#define FLAGS_SET_GEODETIC(flags, value)
Definition: liblwgeom.h:175
#define FLAGS_SET_M(flags, value)
Definition: liblwgeom.h:173
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
#define FLAGS_SET_Z(flags, value)
Definition: liblwgeom.h:172
#define str(s)
void * malloc(YYSIZE_T)
void free(void *)
char * lwstrdup(const char *a)
Definition: lwutil.c:254
static void static void lwreporter lwnotice_var
Definition: lwutil.c:51
static char dumb_toupper(int in)
Definition: lwutil.c:470
lwreporter lwerror_var
Definition: lwutil.c:52
void * lwalloc0(size_t size)
Definition: lwutil.c:234
static char * lwgeomTypeName[]
Definition: lwutil.c:60
void lwgeom_set_debuglogger(lwdebuglogger debuglogger)
Definition: lwutil.c:171
void lwerror(const char *fmt,...)
Definition: lwutil.c:190
void lwnotice(const char *fmt,...)
Definition: lwutil.c:177
char * lwmessage_truncate(char *str, int startpos, int endpos, int maxlength, int truncdirection)
Definition: lwutil.c:274
lwallocator lwalloc_var
Definition: lwutil.c:44
static void * default_allocator(size_t size)
Definition: lwutil.c:89
static void lwdebuglogger lwdebug_var
Definition: lwutil.c:56
int geometry_type_from_string(const char *str, uint8_t *type, int *z, int *m)
Calculate type integer and dimensional flags from string input.
Definition: lwutil.c:495
const char dumb_upper_map[128]
Definition: lwutil.c:468
static void * default_reallocator(void *mem, size_t size)
Definition: lwutil.c:102
void * lwrealloc(void *mem, size_t size)
Definition: lwutil.c:242
void lwfree(void *mem)
Definition: lwutil.c:248
static void default_debuglogger(int level, const char *fmt, va_list ap) __attribute__((format(printf
Definition: lwutil.c:126
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
void lwgeom_set_handlers(lwallocator allocator, lwreallocator reallocator, lwfreeor freeor, lwreporter errorreporter, lwreporter noticereporter)
This function is called by programs which want to set up custom handling for memory management and er...
Definition: lwutil.c:158
#define GEOMTYPE_STRUCT_ARRAY_LEN
Definition: lwutil.c:459
void * lwalloc(size_t size)
Definition: lwutil.c:227
static void static void default_errorreporter(const char *fmt, va_list ap) __attribute__((format(printf
Definition: lwutil.c:142
lwflags_t lwflags(int hasz, int hasm, int geodetic)
Construct a new flags bitmask.
Definition: lwutil.c:477
#define LW_MSG_MAXLEN
Definition: lwutil.c:58
void lwdebug(int level, const char *fmt,...)
Definition: lwutil.c:203
lwfreeor lwfree_var
Definition: lwutil.c:46
static void default_freeor(void *mem)
Definition: lwutil.c:96
lwreallocator lwrealloc_var
Definition: lwutil.c:45
struct geomtype_struct geomtype_struct_array[]
Definition: lwutil.c:376
int32_t clamp_srid(int32_t srid)
Return a valid SRID from an arbitrary integer Raises a notice if what comes out is different from wha...
Definition: lwutil.c:339
static void default_noticereporter(const char *fmt, va_list ap) __attribute__((format(printf
Definition: lwutil.c:117
type
Definition: ovdump.py:42
def fmt
Definition: pixval.py:94