[postgis-commits] svn - r3538 - in trunk: . liblwgeom loader

postgis-commits at postgis.refractions.net postgis-commits at postgis.refractions.net
Mon Jan 19 13:33:15 PST 2009


Author: pramsey
Date: 2009-01-19 13:33:14 -0800 (Mon, 19 Jan 2009)
New Revision: 3538

Added:
   trunk/loader/shp2pgsql-cli.c
   trunk/loader/shp2pgsql-core.c
   trunk/loader/shp2pgsql-core.h
   trunk/loader/shp2pgsql-gui.c
   trunk/loader/stringbuffer.c
   trunk/loader/stringbuffer.h
Modified:
   trunk/configure.ac
   trunk/liblwgeom/liblwgeom.h
   trunk/loader/
   trunk/loader/Makefile.in
   trunk/loader/dbfopen.c
Log:
First revision of the GUI. Configure using --with-gui to enable full GUI build. New core/cli will build by default. Old utilities remain in place for now.


Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2009-01-16 17:58:39 UTC (rev 3537)
+++ trunk/configure.ac	2009-01-19 21:33:14 UTC (rev 3538)
@@ -12,6 +12,7 @@
 
 AC_INIT()
 AC_CONFIG_HEADERS([postgis_config.h])
+AC_CONFIG_MACRO_DIR([macros])
 
 dnl Invoke libtool: we do this as it is the easiest way to find the PIC
 dnl flags required to build liblwgeom
@@ -69,6 +70,9 @@
 AC_SUBST([YACC])
 
 
+dnl ===========================================================================
+dnl Find components needed to build documentation
+dnl ===========================================================================
 dnl
 dnl Search for xsltproc which is required for building documentation
 dnl
@@ -78,7 +82,6 @@
 	AC_MSG_WARN([xsltproc is not installed so documentation cannot be built])
 fi
 
-
 dnl
 dnl Search for db2pdf which is required for building PDF documentation
 dnl
@@ -88,7 +91,6 @@
 	AC_MSG_WARN([db2pdf is not installed so PDF documentation cannot be built])
 fi
 
-
 dnl
 dnl Search for dblatex which is required for building PDF documentation
 dnl
@@ -98,8 +100,6 @@
 	AC_MSG_WARN([dblatex is not installed so PDF documentation cannot be built])
 fi
 
-
-
 dnl
 dnl Allow the user to specify the location of the html/docbook.xsl stylesheet
 dnl
@@ -110,7 +110,8 @@
 
 XSLBASE_AUTO=""
 if test "x$XSLBASE" = "x"; then
-	dnl If the user did not specify a directory for the docbook stylesheet, choose the first directory
+	dnl If the user did not specify a directory for the docbook 
+	dnl stylesheet, choose the first directory
 	dnl that matches from the following list
 	SEARCHPATH="
 		/usr/share/sgml/docbook/xsl-stylesheets 
@@ -124,12 +125,14 @@
 		fi
 	done
 
-	dnl Check to see if the automatically searched paths above located a valid Docbook stylesheet
+	dnl Check to see if the automatically searched paths above located a 
+	dnl valid Docbook stylesheet
 	if test "x$XSLBASE_AUTO" = "x"; then
 		AC_MSG_WARN([could not locate Docbook stylesheets required to build the documentation])
 	fi
 else
-	dnl The user specified an alternate directory so make sure everything looks sensible
+	dnl The user specified an alternate directory so make sure everything 
+	dnl looks sensible
 	if test ! -d "$XSLBASE"; then
 		AC_MSG_ERROR([the docbook stylesheet directory specified using --with-xsldir does not exist])
 	fi 
@@ -140,8 +143,10 @@
 fi
 
 dnl
-dnl If XSLBASE has been set then at this point we know it must be valid and so we can just use it. If XSLBASE_AUTO has been set, and XSLBASE
-dnl is empty then a valid stylesheet was found in XSLBASE_AUTO so we should use that. Otherwise just continue silently with a blank XSLBASE
+dnl If XSLBASE has been set then at this point we know it must be 
+dnl valid and so we can just use it. If XSLBASE_AUTO has been set, and XSLBASE
+dnl is empty then a valid stylesheet was found in XSLBASE_AUTO so we 
+dnl should use that. Otherwise just continue silently with a blank XSLBASE
 dnl variable which will trigger the error message in the documentation Makefile
 dnl
 
@@ -154,14 +159,14 @@
 AC_SUBST([XSLBASE])
 
 
-dnl
+dnl ===========================================================================
 dnl Detect CUnit if it is installed (used for unit testing)
 dnl
-dnl Note that we pass any specified CPPFLAGS and LDFLAGS into the Makefile as CUnit is
-dnl the only compile-time dependency that cannot obtain any specialised flags using
-dnl a --with-X parameter, and so we allow this information to be passed in if
-dnl required.
-dnl
+dnl Note that we pass any specified CPPFLAGS and LDFLAGS into the Makefile 
+dnl as CUnit is the only compile-time dependency that cannot obtain any 
+dnl specialised flags using a --with-X parameter, and so we allow this 
+dnl information to be passed in if required.
+dnl ===========================================================================
 
 CUNIT_LDFLAGS=""
 AC_CHECK_HEADER([CUnit/CUnit.h], [
@@ -176,9 +181,10 @@
 AC_SUBST([CUNIT_LDFLAGS])
 
 
-dnl
-dnl Detect iconv if it is installed (used for shp2pgsql encoding conversion if available)
-dnl
+dnl ===========================================================================
+dnl Detect iconv if it is installed (used for shp2pgsql encoding conversion 
+dnl if available)
+dnl ===========================================================================
 
 HAVE_ICONV_H=0
 AC_CHECK_HEADER([iconv.h], [HAVE_ICONV_H=1], [])
@@ -213,9 +219,9 @@
 AC_SUBST([ICONV_LDFLAGS])
 
 
-dnl
+dnl ===========================================================================
 dnl Detect the version of PostgreSQL installed on the system
-dnl
+dnl ===========================================================================
 
 AC_ARG_WITH([pgconfig], 
 	[AS_HELP_STRING([--with-pgconfig=FILE], [specify an alternative pg_config file])], 
@@ -243,11 +249,12 @@
 fi
 
 
-dnl
-dnl Ensure that $PG_CONFIG --pgxs points to a valid file. This is because some distributions such as Debian
-dnl also include pg_config as part of libpq-dev packages, but don't install the Makefile it points to unless
+dnl ===========================================================================
+dnl Ensure that $PG_CONFIG --pgxs points to a valid file. This is because some 
+dnl distributions such as Debian also include pg_config as part of libpq-dev 
+dnl packages, but don't install the Makefile it points to unless
 dnl the postgresql-server-dev packages are installed :)
-dnl
+dnl ===========================================================================
 
 PGXS=`$PGCONFIG --pgxs`
 if test ! -f $PGXS; then
@@ -316,9 +323,10 @@
 AC_SUBST([POSTGIS_PGSQL_VERSION])
 
 
-dnl
+
+dnl ===========================================================================
 dnl Detect the version of GEOS installed on the system
-dnl
+dnl ===========================================================================
 
 AC_ARG_WITH([geosconfig], 
 	[AS_HELP_STRING([--with-geosconfig=FILE], [specify an alternative geos-config file])], 
@@ -345,9 +353,10 @@
 	fi
 fi
 
-dnl Extract the version information from pg_config
-dnl Note: we extract the major & minor separately, ensure they are numeric, and then combine to give
-dnl the final version. This is to guard against user error... 
+dnl Extract the version information from geos_config
+dnl Note: we extract the major & minor separately, ensure they are numeric, 
+dnl and then combine to give the final version. 
+dnl This is to guard against user error... 
 GEOS_MAJOR_VERSION=`$GEOSCONFIG --version | cut -d. -f1 | sed 's/[[^0-9]]//g'`
 GEOS_MINOR_VERSION=`$GEOSCONFIG --version | cut -d. -f2 | sed 's/[[^0-9]]//g'`
 POSTGIS_GEOS_VERSION="$GEOS_MAJOR_VERSION$GEOS_MINOR_VERSION"
@@ -386,9 +395,9 @@
 AC_SUBST([POSTGIS_GEOS_VERSION])
 
 
-dnl
+dnl ===========================================================================
 dnl Detect the version of PROJ.4 installed
-dnl
+dnl ===========================================================================
 
 AC_ARG_WITH([projdir], 
 	[AS_HELP_STRING([--with-projdir=PATH], [specify the PROJ.4 installation directory])], 
@@ -411,6 +420,7 @@
 	fi
 fi
 
+
 dnl Check that we can find the proj_api.h header file
 CPPFLAGS_SAVE="$CPPFLAGS"
 CPPFLAGS="$PROJ_CPPFLAGS"
@@ -436,8 +446,51 @@
 	[])
 LIBS="$LIBS_SAVE"
 
+dnl ===========================================================================
+dnl Detect GLib GTK for GUI
+dnl ===========================================================================
 
-dnl
+AC_ARG_WITH([gui], 
+	[AS_HELP_STRING([--with-gui], [compile the data import GUI (requires GTK+2.0)])], 
+	[GUI="yes"], [GUI="no"])
+
+if test "x$GUI" = "xyes"; then
+	AC_MSG_RESULT([GUI: Build requested, checking for dependencies (GKT+2.0)])
+	case $host in
+		*apple*)
+			for frmwrk [ in Cairo GLib Gtk ]; do
+				if test -d /Library/Frameworks/${frmwrk}.framework; then
+					GTK_INCLUDES="$GTK_INCLUDES -I/Library/Frameworks/${frmwrk}.framework/Headers" 
+					GTK_LIBS="$GTK_LIBS -framework $frmwrk" 
+					AC_MSG_RESULT([GUI: Found /Library/Frameworks/${frmwrk}.framework])
+				else
+					AC_MSG_ERROR([GUI: Mac OS/X build requires the GTK+2.0 frameworks available from http://www.gtk-osx.org])
+				fi
+			done
+			GTK_BUILD="gui"
+			;;
+		*)
+			dnl Try to find the GTK libs with pkgconfig 
+			if ! test -x `which pkg-config`; then
+				AC_MSG_ERROR([GUI: Building GTK applications requires 'pkg-config', please install it.])
+			else
+				AC_MSG_RESULT([GUI: Running 'pkg-config gtk+-2.0 --cflags'])
+				GTK_INCLUDES=`pkg-config gtk+-2.0 --cflags`
+				AC_MSG_RESULT([GUI: Running 'pkg-config gtk+-2.0 --libs'])
+				GTK_LIBS=`pkg-config gtk+-2.0 --libs`
+				if test ! "x$GTK_LIBS" = "x"; then
+					GTK_BUILD="gui"
+				fi
+			fi
+	esac
+fi
+AC_SUBST([GTK_INCLUDES])
+AC_SUBST([GTK_LIBS])
+AC_SUBST([GTK_BUILD])
+
+
+
+dnl ===========================================================================
 dnl Allow the user to enable debugging with --enable-debug
 dnl
 dnl Currently we default to debug level 4. See DEBUG for more information. 
@@ -448,7 +501,7 @@
 
 AC_DEFINE_UNQUOTED([POSTGIS_DEBUG_LEVEL], [$POSTGIS_DEBUG_LEVEL], [PostGIS library debug level (0=disabled)])
 
-dnl
+dnl ===========================================================================
 dnl Allow the user to enable GEOS profiling with --enable-profile
 dnl
 
@@ -457,7 +510,7 @@
 
 AC_DEFINE_UNQUOTED([POSTGIS_PROFILE], [$POSTGIS_PROFILE], [Enable GEOS profiling (0=disabled)])
 
-dnl
+dnl ===========================================================================
 dnl Define version macros
 dnl
 
@@ -477,7 +530,7 @@
 AC_SUBST([POSTGIS_SCRIPTS_VERSION])
 
 
-dnl
+dnl ===========================================================================
 dnl Other parameters 
 dnl
 

Modified: trunk/liblwgeom/liblwgeom.h
===================================================================
--- trunk/liblwgeom/liblwgeom.h	2009-01-16 17:58:39 UTC (rev 3537)
+++ trunk/liblwgeom/liblwgeom.h	2009-01-19 21:33:14 UTC (rev 3538)
@@ -1274,8 +1274,7 @@
 extern const char *lwgeom_typeflags(uchar type);
 
 /* Construct an empty pointarray */
-extern POINTARRAY *ptarray_construct(char hasz, char hasm,
-	unsigned int npoints);
+extern POINTARRAY *ptarray_construct(char hasz, char hasm, unsigned int npoints);
 
 /*
  * extern POINTARRAY *ptarray_construct2d(uint32 npoints, const POINT2D *pts);


Property changes on: trunk/loader
___________________________________________________________________
Name: svn:ignore
   - pgsql2shp
shp2pgsql
Makefile.shp2pgsql
Makefile.pgsql2shp
Makefile

   + pgsql2shp
shp2pgsql
shp2pgsql-gui
shp2pgsql-cli
Makefile.shp2pgsql
Makefile.pgsql2shp
Makefile


Modified: trunk/loader/Makefile.in
===================================================================
--- trunk/loader/Makefile.in	2009-01-16 17:58:39 UTC (rev 3537)
+++ trunk/loader/Makefile.in	2009-01-19 21:33:14 UTC (rev 3538)
@@ -16,12 +16,9 @@
 # Filenames with extension as determined by the OS
 PGSQL2SHP=pgsql2shp at EXESUFFIX@
 SHP2PGSQL=shp2pgsql at EXESUFFIX@
+SHP2PGSQL-GUI=shp2pgsql-gui at EXESUFFIX@
+SHP2PGSQL-CLI=shp2pgsql-cli at EXESUFFIX@
 
-# Common shapefile library files
-OBJS=	shpopen.o \
-	dbfopen.o \
-	getopt.o
-
 # PostgreSQL frontend CPPFLAGS and LDFLAGS (for compiling and linking with libpq)
 PGSQL_FE_CPPFLAGS=@PGSQL_FE_CPPFLAGS@
 PGSQL_FE_LDFLAGS=@PGSQL_FE_LDFLAGS@
@@ -32,30 +29,51 @@
 # iconv flags
 ICONV_LDFLAGS=@ICONV_LDFLAGS@
 
+# liblwgeom
+LIBLWGEOM=../liblwgeom/liblwgeom.a
 
-all: $(SHP2PGSQL) $(PGSQL2SHP) 
+# GTK includes and libraries
+GTK_INCLUDES = @GTK_INCLUDES@
+GTK_LIBS = @GTK_LIBS@
 
-# liblwgeom.a dependency to allow "make install" in the loader/ subdirectory to work  
-../liblwgeom/liblwgeom.a:
+all: $(SHP2PGSQL) $(PGSQL2SHP) $(SHP2PGSQL-CLI) @GTK_BUILD@
+
+gui: $(SHP2PGSQL-GUI)
+
+# liblwgeom.a dependency to allow "make install" in 
+# the loader/ subdirectory to work  
+$(LIBLWGEOM):
 	make -C ../liblwgeom
 
 pgsql2shp.o: pgsql2shp.c
 	$(CC) $(CFLAGS) $(PGSQL_FE_CPPFLAGS) -c $<
 
-$(PGSQL2SHP): ../liblwgeom/liblwgeom.a $(OBJS) pgsql2shp.o
-	$(CC) $(CFLAGS) $(OBJS) pgsql2shp.o $(ICONV_LDFLAGS) $(PGSQL_FE_LDFLAGS) ../liblwgeom/liblwgeom.a -lm -o $@ 
+$(PGSQL2SHP): shpopen.o dbfopen.o getopt.o pgsql2shp.o $(LIBLWGEOM) 
+	$(CC) $(CFLAGS) $^ $(ICONV_LDFLAGS) $(PGSQL_FE_LDFLAGS) -lm -o $@ 
 
-$(SHP2PGSQL): ../liblwgeom/liblwgeom.a $(OBJS) shp2pgsql.o
-	$(CC) $(CFLAGS) $(OBJS) shp2pgsql.o $(ICONV_LDFLAGS) ../liblwgeom/liblwgeom.a -lm -o $@ 
+$(SHP2PGSQL): shpopen.o dbfopen.o getopt.o  shp2pgsql.o $(LIBLWGEOM) 
+	$(CC) $(CFLAGS) $^ $(ICONV_LDFLAGS) -lm -o $@ 
 
+shp2pgsql-core-gui.o: shp2pgsql-core.c
+	$(CC) $(CFLAGS) -DPGUI -c -o $@ $^
+
+shp2pgsql-gui.o: shp2pgsql-gui.c
+	$(CC) $(PGSQL_FE_CPPFLAGS) $(CFLAGS) $(GTK_INCLUDES) -o $@ -c shp2pgsql-gui.c
+
+$(SHP2PGSQL-GUI): stringbuffer.o shpopen.o dbfopen.o shp2pgsql-core-gui.o shp2pgsql-gui.o $(LIBLWGEOM) 
+	$(CC) $(CFLAGS) $(GTK_LIBS) $(ICONV_LDFLAGS) $(PGSQL_FE_LDFLAGS) -lm $^ -o $@
+
+$(SHP2PGSQL-CLI): stringbuffer.o shpopen.o dbfopen.o shp2pgsql-core.o shp2pgsql-cli.o $(LIBLWGEOM) 
+	$(CC) $(CFLAGS) $(ICONV_LDFLAGS) -lm $^ -o $@
+
 install: all
-	cp $(PGSQL2SHP) $(PGSQL_BINDIR)/$(PGSQL2SHP)
-	cp $(SHP2PGSQL) $(PGSQL_BINDIR)/$(SHP2PGSQL)
+	@cp $(PGSQL2SHP) $(PGSQL_BINDIR)/$(PGSQL2SHP)
+	@cp $(SHP2PGSQL) $(PGSQL_BINDIR)/$(SHP2PGSQL)
 
 uninstall:
-	rm -f $(PGSQL_BINDIR)/$(PGSQL2SHP)
-	rm -f $(PGSQL_BINDIR)/$(SHP2PGSQL)
+	@rm -f $(PGSQL_BINDIR)/$(PGSQL2SHP)
+	@rm -f $(PGSQL_BINDIR)/$(SHP2PGSQL)
 
 clean:
-	rm -f $(OBJS) shp2pgsql.o pgsql2shp.o $(SHP2PGSQL) $(PGSQL2SHP) 
+	@rm -f *.o $(SHP2PGSQL) $(PGSQL2SHP) 
 

Modified: trunk/loader/dbfopen.c
===================================================================
--- trunk/loader/dbfopen.c	2009-01-16 17:58:39 UTC (rev 3537)
+++ trunk/loader/dbfopen.c	2009-01-19 21:33:14 UTC (rev 3538)
@@ -203,9 +203,6 @@
  * Added header.
  */
 
-static char rcsid[] = 
-  "$Id$";
-
 #include "shapefil.h"
 
 #include <math.h>

Added: trunk/loader/shp2pgsql-cli.c
===================================================================
--- trunk/loader/shp2pgsql-cli.c	2009-01-16 17:58:39 UTC (rev 3537)
+++ trunk/loader/shp2pgsql-cli.c	2009-01-19 21:33:14 UTC (rev 3538)
@@ -0,0 +1,224 @@
+/**********************************************************************
+ * $Id: shp2pgsql-gui.c 3450 2008-12-18 20:42:09Z pramsey $
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2008 OpenGeo.org
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ * Maintainer: Paul Ramsey <pramsey at opengeo.org>
+ *
+ **********************************************************************/
+
+#include <unistd.h>
+#include "shp2pgsql-core.h"
+
+static void
+pcli_usage(char *me, int exitcode, FILE* out)
+{
+    fprintf(out, "RCSID: %s RELEASE: %s\n", RCSID, POSTGIS_VERSION);
+	fprintf(out, "USAGE: %s [<options>] <shapefile> [<schema>.]<table>\n", me);
+	fprintf(out, "OPTIONS:\n");
+	fprintf(out, "  -s <srid>  Set the SRID field. If not specified it defaults to -1.\n");
+	fprintf(out, "  (-d|a|c|p) These are mutually exclusive options:\n");
+	fprintf(out, "      -d  Drops the table, then recreates it and populates\n");
+	fprintf(out, "          it with current shape file data.\n");
+	fprintf(out, "      -a  Appends shape file into current table, must be\n");
+	fprintf(out, "          exactly the same table schema.\n");
+	fprintf(out, "      -c  Creates a new table and populates it, this is the\n");
+	fprintf(out, "          default if you do not specify any options.\n");
+ 	fprintf(out, "      -p  Prepare mode, only creates the table.\n");
+	fprintf(out, "  -g <geometry_column> Specify the name of the geometry column\n");
+	fprintf(out, "     (mostly useful in append mode).\n");
+	fprintf(out, "  -D  Use postgresql dump format (defaults to sql insert statments.\n");
+	fprintf(out, "  -k  Keep postgresql identifiers case.\n");
+	fprintf(out, "  -i  Use int4 type for all integer dbf fields.\n");
+	fprintf(out, "  -I  Create a GiST index on the geometry column.\n");
+	fprintf(out, "  -S  Generate simple geometries instead of MULTI geometries.\n");
+#ifdef HAVE_ICONV
+	fprintf(out, "  -W <encoding> Specify the character encoding of Shape's\n");
+	fprintf(out, "     attribute column. (default : \"ASCII\")\n");
+#endif
+	fprintf(out, "  -N <policy> Specify NULL geometries handling policy (insert,skip,abort)\n");
+	fprintf(out, "  -n  Only import DBF file.\n");
+    fprintf(out, "  -? Display this help screen\n");
+	exit (exitcode);
+}
+
+
+static int
+pcli_cmdline(int ARGC, char **ARGV)
+{
+	int c;
+	int curindex=0;
+	char  *ptr;
+	extern char *optarg;
+	extern int optind;
+
+	if ( ARGC == 1 ) {
+		pcli_usage(ARGV[0], 0, stdout);
+	}
+
+	while ((c = getopt(ARGC, ARGV, "kcdapDs:Sg:iW:wIN:n")) != EOF){
+		switch (c) {
+			case 'c':
+				if (opt == ' ')
+					 opt ='c';
+				else
+					 return 0;
+				break;
+			case 'd':
+				if (opt == ' ')
+					 opt ='d';
+				else
+					 return 0;
+				break;
+			case 'a':
+				if (opt == ' ')
+					 opt ='a';
+				else
+					 return 0;
+				break;
+			case 'p':
+				if (opt == ' ')
+					 opt ='p';
+				else
+					 return 0;
+				break;
+			case 'D':
+				dump_format =1;
+				break;
+			case 'S':
+				simple_geometries =1;
+				break;
+			case 's':
+				if( optarg ) 
+					(void)sscanf(optarg, "%d", &sr_id);
+				else 
+					pcli_usage(ARGV[0], 0, stdout); 
+				break;
+			case 'g':
+				geom = optarg;
+				break;
+			case 'k':
+				quoteidentifiers = 1;
+				break;
+			case 'i':
+				forceint4 = 1;
+				break;
+			case 'I':
+				createindex = 1;
+				break;
+			case 'n':
+				readshape = 0;
+				break;
+			case 'W':
+#ifdef HAVE_ICONV
+				encoding = optarg;
+#else
+				fprintf(stderr, "WARNING: the -W switch will have no effect. UTF8 disabled at compile time\n");
+#endif
+				break;
+			case 'N':
+				switch (optarg[0])
+				{	
+					case 'a':
+						null_policy = abort_on_null;
+						break;
+					case 'i':
+						null_policy = insert_null;
+						break;
+					case 's':
+						null_policy = skip_null;
+						break;
+					default:
+						fprintf(stderr, "Unsupported NULL geometry handling policy.\nValid policies: insert, skip, abort\n");
+						exit(1);
+				}
+				break;
+			case '?':
+				pcli_usage(ARGV[0], 0, stdout); 
+			default:              
+				return 0;
+		}
+	}
+
+	if ( !sr_id ) sr_id = -1;
+
+	if ( !geom ) geom = "the_geom";
+
+	if ( opt==' ' ) opt = 'c';
+
+	for (; optind < ARGC; optind++){
+		if(curindex ==0){
+			shp_file = ARGV[optind];
+		}else if(curindex == 1){
+			table = ARGV[optind];
+			if ( (ptr=strchr(table, '.')) )
+			{
+				*ptr = '\0';
+				schema = table;
+				table = ptr+1;
+			}
+		}
+		curindex++;
+	}
+	
+	/*
+	 * Third argument (if present) is supported for compatibility
+	 * with old shp2pgsql versions taking also database name.
+	 */
+	if(curindex < 2 || curindex > 3){
+		return 0;
+	}
+
+	/* 
+	 * Transform table name to lower case unless asked
+	 * to keep original case (we'll quote it later on)
+	 */
+	if ( ! quoteidentifiers )
+	{
+		LowerCase(table);
+		if ( schema ) LowerCase(schema);
+	}
+
+	return 1;
+}
+
+int
+main (int ARGC, char **ARGV)
+{
+
+	int rv = 0;
+
+	/* Emit output to stdout/stderr, not a GUI */
+	gui_mode = 0;
+
+	/* Parse command line options and set globals */
+	if ( ! pcli_cmdline(ARGC, ARGV) ) pcli_usage(ARGV[0], 2, stderr);
+
+	/* Set record number to beginning of file, and translation stage to first one */
+	cur_entity = -1;
+	translation_stage = 1;
+	
+	rv = translation_start();
+	if( ! rv ) return 1;
+	while( translation_stage == 2 ) 
+	{
+		rv = translation_middle();
+		if( ! rv ) return 1;
+	}
+	rv = translation_end();
+	if( ! rv ) return 1;
+
+	return 0;
+
+}
+
+
+/**********************************************************************
+ * $Log$
+ *
+ **********************************************************************/

Added: trunk/loader/shp2pgsql-core.c
===================================================================
--- trunk/loader/shp2pgsql-core.c	2009-01-16 17:58:39 UTC (rev 3537)
+++ trunk/loader/shp2pgsql-core.c	2009-01-19 21:33:14 UTC (rev 3538)
@@ -0,0 +1,1862 @@
+/**********************************************************************
+ * $Id: shp2pgsql.c 3450 2008-12-18 20:42:09Z pramsey $
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2001-2003 Refractions Research Inc.
+ * Copyright 2008 OpenGeo.org
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************
+ * Using shapelib 1.2.8, this program reads in shape files and
+ * processes it's contents into a Insert statements which can be
+ * easily piped into a database frontend.
+ * Specifically designed to insert type 'geometry' (a custom
+ * written PostgreSQL type) for the shape files and PostgreSQL
+ * standard types for all attributes of the entity.
+ *
+ * Maintainer: Paul Ramsey <pramsey at opengeo.org>
+ * Original Author: Jeff Lounsbury <jeffloun at refractions.net>
+ *
+ **********************************************************************/
+
+#include "../postgis_config.h"
+#include "shp2pgsql-core.h"
+
+#define	POINTTYPE	1
+#define	LINETYPE	2
+#define	POLYGONTYPE	3
+#define	MULTIPOINTTYPE	4
+#define	MULTILINETYPE	5
+#define	MULTIPOLYGONTYPE	6
+#define	COLLECTIONTYPE	7
+
+#define WKBZOFFSET 0x80000000
+#define WKBMOFFSET 0x40000000
+
+typedef struct
+{
+	double x, y, z, m;
+}
+Point;
+
+typedef struct Ring
+{
+	Point *list;		/* list of points */
+	struct Ring  *next;
+	int n;			/* number of points in list */
+	unsigned int linked; 	/* number of "next" rings */
+}
+Ring;
+
+
+/* Public globals */
+int dump_format = 0; /* 0 = SQL inserts, 1 = dump */
+int simple_geometries = 0; /* 0 = MULTIPOLYGON/MULTILINESTRING, 1 = force to POLYGON/LINESTRING */
+int quoteidentifiers = 0; /* 0 = columnname, 1 = "columnName" */
+int forceint4 = 0; /* 0 = allow int8 fields, 1 = no int8 fields */
+int createindex = 0; /* 0 = no index, 1 = create index after load */
+int readshape = 1; /* 0 = load DBF file only, 1 = load everything */
+char opt = ' '; /* load mode: c = create, d = delete, a = append, p = prepare */
+char *table = NULL; /* table to load into */
+char *schema = NULL; /* schema to load into */
+char *geom = NULL; /* geometry column name to use */
+#ifdef HAVE_ICONV
+char *encoding = NULL; /* iconv encoding name */
+#endif
+int null_policy = insert_null; /* how to handle nulls */
+int sr_id = 0; /* SRID specified */
+char *shp_file = NULL; /* the shape file (without the .shp extension) */
+int gui_mode = 0; /* 1 = GUI, 0 = commandline */
+int translation_stage = 0;
+
+/* Private globals */
+stringbuffer_t *sb_row; /* stringbuffer to append results to */
+char    *col_names = NULL;
+char	*pgtype;
+int	istypeM = 0;
+int	pgdims;
+unsigned int wkbtype;
+DBFFieldType *types;	/* Fields type, width and precision */
+SHPHandle  hSHPHandle;
+DBFHandle  hDBFHandle;
+int shpfiletype;
+SHPObject  *obj=NULL;
+int 	*widths;
+int 	*precisions;
+int     num_fields,num_records,num_entities;
+int cur_entity = -1;
+char    **field_names;
+
+
+/* Prototypes */
+int Insert_attributes(DBFHandle hDBFHandle, int row);
+char *make_good_string(char *str);
+char *protect_quotes_string(char *str);
+int PIP( Point P, Point* V, int n );
+int CreateTable(void);
+int CreateIndex(void);
+void usage(char *me, int exitcode, FILE* out);
+int InsertPoint(void);
+int InsertPolygon(void);
+int InsertLineString(void);
+int OutputGeometry(char *geometry);
+void SetPgType(void);
+#ifdef HAVE_ICONV
+char *utf8(const char *fromcode, char *inputbuf);
+#endif
+int FindPolygons(SHPObject *obj, Ring ***Out);
+void ReleasePolygons(Ring **polys, int npolys);
+int DropTable(char *schema, char *table, char *geom);
+void GetFieldsSpec(void);
+int LoadData(void);
+int OpenShape(void);
+void LowerCase(char *s);
+void Cleanup(void);
+
+static int
+pgis_exec(const char *sql)
+{
+#ifdef PGUI
+	return pgui_exec(sql);
+#else
+	printf("%s;\n", sql);
+	return 1;
+#endif
+}
+
+static int
+pgis_copy_write(const char *line)
+{
+#ifdef PGUI
+	return pgui_copy_write(line);
+#else
+	printf("%s", line);
+	return 1;
+#endif
+}
+
+static int
+pgis_copy_start(const char *sql)
+{
+#ifdef PGUI
+	return pgui_copy_start(sql);
+#else
+	printf("%s;\n", sql);
+	return 1;
+#endif
+}
+
+static int
+pgis_copy_end(const int rollback)
+{
+#ifdef PGUI
+	return pgui_copy_end(rollback);
+#else
+	printf("\\.\n");
+	return 1;
+#endif
+}
+
+static void
+pgis_logf(const char *fmt, ... )
+{
+#ifndef PGUI
+	char *msg;
+#endif
+	va_list ap;
+
+	va_start(ap, fmt);
+
+#ifdef PGUI
+	pgui_log_va(fmt, ap);
+#else
+	if (!vasprintf (&msg, fmt, ap))
+	{
+		va_end (ap);
+		return;
+	}
+	fprintf(stderr, "%s\n", msg);
+	free(msg);
+#endif
+	va_end(ap);
+}
+
+/* liblwgeom allocator callback - install the defaults (malloc/free/stdout/stderr) */
+/* TODO hook lwnotice/lwerr up to the GUI */
+void lwgeom_init_allocators()
+{
+	lwgeom_install_default_allocators();
+}
+
+char *
+make_good_string(char *str)
+{
+	/*
+	 * find all the tabs and make them \<tab>s
+	 *
+	 * 1. find # of tabs
+	 * 2. make new string 
+	 *
+	 * we dont escape already escaped tabs
+	 */
+
+	char *result;
+	char *ptr, *optr;
+	int toescape = 0;
+	size_t size;
+#ifdef HAVE_ICONV
+	char *utf8str=NULL;
+
+	if ( encoding )
+	{
+		utf8str=utf8(encoding, str);
+		if ( ! utf8str ) exit(1);
+		str = utf8str;
+	}
+#endif
+
+	ptr = str;
+
+	while (*ptr)
+	{
+		if ( *ptr == '\t' || *ptr == '\\' ) toescape++;
+		ptr++;
+	}
+
+	if (toescape == 0) return str;
+
+	size = ptr-str+toescape+1;
+
+	result = calloc(1, size);
+
+	optr=result;
+	ptr=str;
+	while (*ptr)
+	{
+		if ( *ptr == '\t' || *ptr == '\\' ) *optr++='\\';
+		*optr++=*ptr++;
+	}
+	*optr='\0';
+
+#ifdef HAVE_ICONV
+	if ( encoding ) free(str);
+#endif
+
+	return result;
+
+}
+
+char *
+protect_quotes_string(char *str)
+{
+	/*
+	 * find all quotes and make them \quotes
+	 * find all '\' and make them '\\'
+	 * 
+	 * 1. find # of characters
+	 * 2. make new string 
+	 */
+
+	char	*result;
+	char	*ptr, *optr;
+	int	toescape = 0;
+	size_t size;
+#ifdef HAVE_ICONV
+	char *utf8str=NULL;
+
+	if ( encoding )
+	{
+		utf8str=utf8(encoding, str);
+		if ( ! utf8str ) exit(1);
+		str = utf8str;
+	}
+#endif
+
+	ptr = str;
+
+	while (*ptr)
+	{
+		if ( *ptr == '\'' || *ptr == '\\' ) toescape++;
+		ptr++;
+	}
+
+	if (toescape == 0) return str;
+
+	size = ptr-str+toescape+1;
+
+	result = calloc(1, size);
+
+	optr=result;
+	ptr=str;
+	while (*ptr)
+	{
+		if ( *ptr == '\\' ) *optr++='\\';
+		if ( *ptr == '\'') *optr++='\'';
+		*optr++=*ptr++;
+	}
+	*optr='\0';
+
+#ifdef HAVE_ICONV
+	if ( encoding ) free(str);
+#endif
+
+	return result;
+}
+
+
+
+/*
+ * PIP(): crossing number test for a point in a polygon
+ *      input:   P = a point,
+ *               V[] = vertex points of a polygon V[n+1] with V[n]=V[0]
+ *      returns: 0 = outside, 1 = inside
+ */
+int
+PIP( Point P, Point* V, int n )
+{
+	int cn = 0;    /* the crossing number counter */
+	int i;
+
+	/* loop through all edges of the polygon */
+	for (i=0; i<n-1; i++)
+	{    /* edge from V[i] to V[i+1] */
+		if (((V[i].y <= P.y) && (V[i+1].y > P.y))    /* an upward crossing */
+		        || ((V[i].y > P.y) && (V[i+1].y <= P.y)))
+		{ /* a downward crossing */
+			double vt = (float)(P.y - V[i].y) / (V[i+1].y - V[i].y);
+			if (P.x < V[i].x + vt * (V[i+1].x - V[i].x)) /* P.x < intersect */
+				++cn;   /* a valid crossing of y=P.y right of P.x */
+		}
+	}
+	return (cn&1);    /* 0 if even (out), and 1 if odd (in) */
+
+}
+
+
+
+
+
+int
+Insert_attributes(DBFHandle hDBFHandle, int row)
+{
+	int i,num_fields;
+	char val[1024];
+	char *escval;
+
+	num_fields = DBFGetFieldCount( hDBFHandle );
+	for ( i = 0; i < num_fields; i++ )
+	{
+		if (DBFIsAttributeNULL( hDBFHandle, row, i))
+		{
+			if (dump_format)
+			{
+				stringbuffer_append(sb_row, "\\N");
+			}
+			else
+			{
+				stringbuffer_append(sb_row, "NULL");
+			}
+		}
+		else /* Attribute NOT NULL */
+		{
+			switch (types[i])
+			{
+			case FTInteger:
+			case FTDouble:
+				if ( -1 == snprintf(val, 1024, "%s", DBFReadStringAttribute(hDBFHandle, row, i)) )
+				{
+					pgis_logf("Warning: field %d name truncated", i);
+					val[1023] = '\0';
+				}
+				/* pg_atoi() does not do this */
+				if ( val[0] == '\0' )
+				{
+					val[0] = '0';
+					val[1] = '\0';
+				}
+				if ( val[strlen(val)-1] == '.' ) val[strlen(val)-1] = '\0';
+				break;
+
+			case FTString:
+			case FTLogical:
+			case FTDate:
+				if ( -1 == snprintf(val, 1024, "%s", DBFReadStringAttribute(hDBFHandle, row, i)) )
+				{
+					pgis_logf("Warning: field %d name truncated", i);
+					val[1023] = '\0';
+				}
+				break;
+
+			default:
+				pgis_logf(
+				    "Error: field %d has invalid or unknown field type (%d)",
+				    i, types[i]);
+				return 0;
+			}
+			
+			if (dump_format)
+			{
+				escval = make_good_string(val);
+				stringbuffer_aprintf(sb_row, "%s", escval);
+				//printf("\t");
+			}
+			else
+			{
+				escval = protect_quotes_string(val);
+				stringbuffer_aprintf(sb_row, "'%s'", escval);
+				//printf(",");
+			}
+			if ( val != escval ) free(escval);
+		}
+		//only put in delimeter if not last field or a shape will follow
+		if (readshape == 1 || i < (num_fields - 1))
+		{
+			if (dump_format)
+			{
+				stringbuffer_append_c(sb_row, '\t');
+			}
+			else
+			{
+				stringbuffer_append_c(sb_row, ',');
+			}
+		}
+	}
+	return 1;
+}
+
+
+
+
+/*
+ * formerly main()
+ */
+int
+translation_start ()
+{
+
+	sb_row = stringbuffer_create();
+
+	/*
+	 * Open shapefile and initialize globals
+	 */
+	if ( ! OpenShape() )
+		return 0;
+
+	if (readshape == 1)
+	{
+		/*
+		 * Compute output geometry type
+		 */
+
+		SetPgType();
+
+		pgis_logf("Shapefile type: %s", SHPTypeName(shpfiletype));
+		pgis_logf("PostGIS type: %s [%dD]", pgtype, pgdims);
+	}
+
+#ifdef HAVE_ICONV
+	if ( encoding )
+	{
+		if ( ! pgis_exec("SET CLIENT_ENCODING TO UTF8") ) return 0;
+	}
+#endif /* defined HAVE_ICONV */
+
+	/*
+	 * Drop table if requested
+	 */
+	if (opt == 'd')
+		if ( ! DropTable(schema, table, geom) )
+			return 0;
+
+	/*
+	 * Get col names and types for table creation
+	 * and data load.
+	 */
+	GetFieldsSpec();
+
+	if ( ! pgis_exec("BEGIN") ) return 0;
+
+	/*
+	 * If not in 'append' mode create the spatial table
+	 */
+	if (opt != 'a')
+		if ( ! CreateTable() )
+			return 0;
+
+	translation_stage = 2; /* done start */
+	return 1;
+}
+
+int
+translation_middle()
+{
+	/*
+	 * Generate INSERT or COPY lines
+	 */
+	if (opt != 'p')
+	{
+		if ( ! LoadData() )
+			return 0;
+	}
+	else
+	{
+		translation_stage = 3; /* done middle */
+	}
+	return 1;
+}
+
+int
+translation_end()
+{
+	/*
+	 * Create GiST index if requested
+	 */
+	if (createindex)
+		if ( ! CreateIndex() )
+			return 0;
+
+	if ( ! pgis_exec("END") ) return 0; /* End the last transaction */
+
+	translation_stage = 4;
+
+	return 1;
+}
+
+void
+LowerCase(char *s)
+{
+	int j;
+	for (j=0; j<strlen(s); j++) s[j] = tolower(s[j]);
+}
+
+void
+Cleanup(void)
+{
+	if ( col_names ) free(col_names);
+}
+
+int
+OpenShape(void)
+{
+	int j;
+	SHPObject *obj=NULL;
+
+	if (readshape == 1)
+	{
+		hSHPHandle = SHPOpen( shp_file, "rb" );
+		if (hSHPHandle == NULL)
+		{
+			pgis_logf("%s: shape (.shp) or index files (.shx) can not be opened, will just import attribute data.", shp_file);
+			readshape = 0;
+		}
+	}
+
+	hDBFHandle = DBFOpen( shp_file, "rb" );
+	if ((hSHPHandle == NULL && readshape == 1) || hDBFHandle == NULL)
+	{
+		pgis_logf("%s: dbf file (.dbf) can not be opened.",shp_file);
+		return 0;
+	}
+
+	if (readshape == 1)
+	{
+		SHPGetInfo(hSHPHandle, &num_entities, &shpfiletype, NULL, NULL);
+
+		if ( null_policy == abort_on_null )
+		{
+			for (j=0; j<num_entities; j++)
+			{
+				obj = SHPReadObject(hSHPHandle,j);
+				if ( ! obj )
+				{
+					pgis_logf("Error reading shape object %d", j);
+					return 0;
+				}
+				if ( obj->nVertices == 0 )
+				{
+					pgis_logf("Empty geometries found, aborted.");
+					return 0;
+				}
+				SHPDestroyObject(obj);
+			}
+		}
+	}
+	else
+	{
+		num_entities = DBFGetRecordCount(hDBFHandle);
+	}
+
+	return 1;
+}
+
+int
+CreateTable(void)
+{
+	int j;
+	int field_precision, field_width;
+	DBFFieldType type = -1;
+
+	/*
+	 * Create a table for inserting the shapes into with appropriate
+	 * columns and types
+	 */
+
+	stringbuffer_clear(sb_row);
+
+	if ( schema )
+	{
+		stringbuffer_aprintf(sb_row, "CREATE TABLE \"%s\".\"%s\" (gid serial PRIMARY KEY", schema, table);
+	}
+	else
+	{
+		stringbuffer_aprintf(sb_row, "CREATE TABLE \"%s\" (gid serial PRIMARY KEY", table);
+	}
+
+	for (j=0;j<num_fields;j++)
+	{
+		type = types[j];
+		field_width = widths[j];
+		field_precision = precisions[j];
+
+		stringbuffer_aprintf(sb_row, ",\n\"%s\" ", field_names[j]);
+
+		if (type == FTString)
+		{
+			/* use DBF attribute size as maximum width */
+			stringbuffer_aprintf (sb_row, "varchar(%d)", field_width);
+		}
+		else if (type == FTDate)
+		{
+			stringbuffer_append (sb_row, "date");
+		}
+		else if (type == FTInteger)
+		{
+			if ( forceint4 )
+			{
+				stringbuffer_append (sb_row, "int4");
+			}
+			else if  ( field_width < 5 )
+			{
+				stringbuffer_append (sb_row, "int2");
+			}
+			else if  ( field_width < 10 )
+			{
+				stringbuffer_append (sb_row, "int4");
+			}
+			else if  ( field_width < 19 )
+			{
+				stringbuffer_append (sb_row, "int8");
+			}
+			else
+			{
+				stringbuffer_aprintf (sb_row, "numeric(%d,0)", field_width);
+			}
+		}
+		else if (type == FTDouble)
+		{
+			if ( field_width > 18 )
+			{
+				stringbuffer_append (sb_row, "numeric");
+			}
+			else
+			{
+				stringbuffer_append (sb_row, "float8");
+			}
+		}
+		else if (type == FTLogical)
+		{
+			stringbuffer_append (sb_row, "boolean");
+		}
+		else
+		{
+			pgis_logf ("Invalid type in DBF file");
+		}
+	}
+	/* Run the CREATE TABLE statement in the buffer and clear. */
+	stringbuffer_append_c(sb_row, ')');
+	if ( ! pgis_exec(stringbuffer_getstring(sb_row)) ) return 0;
+	stringbuffer_clear(sb_row);
+
+	/* Create the geometry column with an addgeometry call */
+	if ( schema && readshape == 1 )
+	{
+		stringbuffer_aprintf(sb_row, "SELECT AddGeometryColumn('%s','%s','%s','%d',",
+		                     schema, table, geom, sr_id);
+	}
+	else if (readshape == 1)
+	{
+		stringbuffer_aprintf(sb_row, "SELECT AddGeometryColumn('','%s','%s','%d',",
+		                     table, geom, sr_id);
+	}
+	if (pgtype)
+	{ //pgtype will only be set if we are loading geometries
+		stringbuffer_aprintf(sb_row, "'%s',%d)", pgtype, pgdims);
+	}
+
+	/* Run the AddGeometryColumn() statement in the buffer and clear. */
+	if ( ! pgis_exec(stringbuffer_getstring(sb_row)) ) return 0;
+	stringbuffer_clear(sb_row);
+
+	return 1;
+}
+
+int
+CreateIndex(void)
+{
+
+	stringbuffer_clear(sb_row);
+
+	if ( schema )
+	{
+		stringbuffer_aprintf(sb_row, "CREATE INDEX \"%s_%s_gist\" ON \"%s\".\"%s\" using gist (\"%s\" gist_geometry_ops)", table, geom, schema, table, geom);
+	}
+	else
+	{
+		stringbuffer_aprintf(sb_row, "CREATE INDEX \"%s_%s_gist\" ON \"%s\" using gist (\"%s\" gist_geometry_ops)", table, geom, table, geom);
+	}
+
+	/* Run the CREATE INDEX statement in the buffer and clear. */
+	if ( ! pgis_exec(stringbuffer_getstring(sb_row)) ) return 0;
+	stringbuffer_clear(sb_row);
+
+	return 1;
+}
+
+int
+LoadData(void)
+{
+	int trans=0;
+
+	if (cur_entity == -1 && dump_format)
+	{
+		char *copysql;
+		if ( schema )
+		{
+			asprintf(&copysql, "COPY \"%s\".\"%s\" %s FROM stdin",
+			         schema, table, col_names);
+		}
+		else
+		{
+			asprintf(&copysql, "COPY \"%s\" %s FROM stdin",
+			         table, col_names);
+		}
+		pgis_copy_start(copysql);
+		free(copysql);
+	}
+
+	/**************************************************************
+	 * 
+	 *   MAIN SHAPE OBJECTS SCAN
+	 * 
+	 **************************************************************/
+	while (cur_entity <  num_entities - 1)
+	{
+
+		cur_entity++;
+
+		/*wrap a transaction block around each 250 inserts... */
+		if ( ! dump_format )
+		{
+			if (trans == 250)
+			{
+				trans=0;
+				if ( ! pgis_exec("END") ) return 0;
+				if ( ! pgis_exec("BEGIN") ) return 0;
+			}
+		}
+		trans++;
+		/* transaction stuff done */
+
+		if ( gui_mode && ( cur_entity % 200 == 0 ) )
+		{
+			pgis_logf("Feature #%d", cur_entity);
+		}
+
+		/* skip the record if it has been deleted */
+		if (readshape != 1 && DBFReadDeleted(hDBFHandle, cur_entity))
+		{
+			continue;
+		}
+
+		/* open the next object */
+		if (readshape == 1)
+		{
+			obj = SHPReadObject(hSHPHandle,cur_entity);
+			if ( ! obj )
+			{
+				pgis_logf("Error reading shape object %d", cur_entity);
+				return 0;
+			}
+
+			if ( null_policy == skip_null && obj->nVertices == 0 )
+			{
+				SHPDestroyObject(obj);
+				continue;
+			}
+		}
+
+		/* New row, clear the stringbuffer. */
+		stringbuffer_clear(sb_row);
+
+		if (!dump_format)
+		{
+			if ( schema )
+			{
+				stringbuffer_aprintf(sb_row, "INSERT INTO \"%s\".\"%s\" %s VALUES (",
+				                     schema, table, col_names);
+			}
+			else
+			{
+				stringbuffer_aprintf(sb_row, "INSERT INTO \"%s\" %s VALUES (",
+				                     table, col_names);
+			}
+		}
+		if ( ! Insert_attributes(hDBFHandle,cur_entity) ) return 0;
+
+		if (readshape == 1)
+		{
+			/* ---------- NULL SHAPE ----------------- */
+			if (obj->nVertices == 0)
+			{
+				if (dump_format)
+				{
+					stringbuffer_append(sb_row, "\\N\n");
+					pgis_copy_write(stringbuffer_getstring(sb_row));
+				}
+				else
+				{
+					stringbuffer_append(sb_row, "NULL)");
+					if ( ! pgis_exec(stringbuffer_getstring(sb_row)) ) return 0;
+				}
+				SHPDestroyObject(obj);
+				continue;
+			}
+
+			switch (obj->nSHPType)
+			{
+			case SHPT_POLYGON:
+			case SHPT_POLYGONM:
+			case SHPT_POLYGONZ:
+				if ( ! InsertPolygon() ) return 0;
+				break;
+
+			case SHPT_POINT:
+			case SHPT_POINTM:
+			case SHPT_POINTZ:
+			case SHPT_MULTIPOINT:
+			case SHPT_MULTIPOINTM:
+			case SHPT_MULTIPOINTZ:
+				if ( ! InsertPoint() ) return 0;
+				break;
+
+			case SHPT_ARC:
+			case SHPT_ARCM:
+			case SHPT_ARCZ:
+				if ( ! InsertLineString() ) return 0;
+				break;
+
+			default:
+				pgis_logf ("**** Type is NOT SUPPORTED, type id = %d ****",
+				           obj->nSHPType);
+				break;
+
+			}
+
+			SHPDestroyObject(obj);
+		}
+		else
+		{
+			if ( dump_format )
+			{   /* close for dbf only dump format */
+				stringbuffer_append_c(sb_row, '\n');
+				pgis_copy_write(stringbuffer_getstring(sb_row));
+			}
+			else
+			{   /* close for dbf only sql insert format */
+				if ( ! pgis_exec(stringbuffer_getstring(sb_row)) ) return 0;
+			}
+		}
+
+		/* Just do 100 entries at a time, then return to the idle loop. */
+		if ( cur_entity % 100 == 0 ) return 1;
+
+	} /* END of MAIN SHAPE OBJECT LOOP */
+
+	if ( dump_format )
+	{
+		pgis_copy_end(0);
+	}
+
+	translation_stage = 3; /* done middle */
+
+	return 1;
+}
+
+
+int
+InsertLineString()
+{
+	LWCOLLECTION *lwcollection;
+
+	LWGEOM **lwmultilinestrings;
+	uchar *serialized_lwgeom;
+	LWGEOM_UNPARSER_RESULT lwg_unparser_result;
+
+	DYNPTARRAY **dpas;
+	POINT4D point4d;
+
+	int dims = 0, hasz = 0, hasm = 0;
+	int result;
+	int u, v, start_vertex, end_vertex;
+
+	if (wkbtype & WKBZOFFSET) hasz = 1;
+	if (wkbtype & WKBMOFFSET) hasm = 1;
+	TYPE_SETZM(dims, hasz, hasm);
+
+	if (simple_geometries == 1 && obj->nParts > 1)
+	{
+		pgis_logf("We have a Multilinestring with %d parts, can't use -S switch!", obj->nParts);
+		return 0;
+	}
+
+	/* Allocate memory for our array of LWLINEs and our dynptarrays */
+	lwmultilinestrings = malloc(sizeof(LWPOINT *) * obj->nParts);
+	dpas = malloc(sizeof(DYNPTARRAY *) * obj->nParts);
+
+	/* We need an array of pointers to each of our sub-geometries */
+	for (u = 0; u < obj->nParts; u++)
+	{
+		/* Create a dynptarray containing the line points */
+		dpas[u] = dynptarray_create(obj->nParts, dims);
+
+		/* Set the start/end vertices depending upon whether this is
+		a MULTILINESTRING or not */
+		if ( u == obj->nParts-1 )
+			end_vertex = obj->nVertices;
+		else
+			end_vertex = obj->panPartStart[u + 1];
+
+		start_vertex = obj->panPartStart[u];
+
+		for (v = start_vertex; v < end_vertex; v++)
+		{
+			/* Generate the point */
+			point4d.x = obj->padfX[v];
+			point4d.y = obj->padfY[v];
+
+			if (wkbtype & WKBZOFFSET)
+				point4d.z = obj->padfZ[v];
+			if (wkbtype & WKBMOFFSET)
+				point4d.m = obj->padfM[v];
+
+			dynptarray_addPoint4d(dpas[u], &point4d, 0);
+		}
+
+		/* Generate the LWLINE */
+		lwmultilinestrings[u] = lwline_as_lwgeom(lwline_construct(sr_id, NULL, dpas[u]->pa));
+	}
+
+	/* If using MULTILINESTRINGs then generate the serialized collection, otherwise just a single LINESTRING */
+	if (simple_geometries == 0)
+	{
+		lwcollection = lwcollection_construct(MULTILINETYPE, sr_id, NULL, obj->nParts, lwmultilinestrings);
+		serialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection));
+	}
+	else
+	{
+		serialized_lwgeom = lwgeom_serialize(lwmultilinestrings[0]);
+	}
+
+	result = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL, -1);
+
+	if (result)
+	{
+		pgis_logf("ERROR: %s", lwg_unparser_result.message);
+		return 0;
+	}
+
+	if ( ! OutputGeometry(lwg_unparser_result.wkoutput) ) return 0;
+
+	/* Free all of the allocated items */
+	lwfree(lwg_unparser_result.wkoutput);
+	lwfree(serialized_lwgeom);
+
+	for (u = 0; u < obj->nParts; u++)
+	{
+		lwline_free(lwgeom_as_lwline(lwmultilinestrings[u]));
+		lwfree(dpas[u]);
+	}
+
+	lwfree(dpas);
+	lwfree(lwmultilinestrings);
+
+	return 1;
+}
+
+int
+FindPolygons(SHPObject *obj, Ring ***Out)
+{
+	Ring **Outer;    /* Pointers to Outer rings */
+	int out_index=0; /* Count of Outer rings */
+	Ring **Inner;    /* Pointers to Inner rings */
+	int in_index=0;  /* Count of Inner rings */
+	int pi; /* part index */
+
+#if POSTGIS_DEBUG_LEVEL > 0
+	static int call = -1;
+	call++;
+#endif
+
+	LWDEBUGF(4, "FindPolygons[%d]: allocated space for %d rings\n", call, obj->nParts);
+
+	/* Allocate initial memory */
+	Outer = (Ring**)malloc(sizeof(Ring*)*obj->nParts);
+	Inner = (Ring**)malloc(sizeof(Ring*)*obj->nParts);
+
+	/* Iterate over rings dividing in Outers and Inners */
+	for (pi=0; pi<obj->nParts; pi++)
+	{
+		int vi; /* vertex index */
+		int vs; /* start index */
+		int ve; /* end index */
+		int nv; /* number of vertex */
+		double area = 0.0;
+		Ring *ring;
+
+		/* Set start and end vertexes */
+		if ( pi==obj->nParts-1 ) ve = obj->nVertices;
+		else ve = obj->panPartStart[pi+1];
+		vs = obj->panPartStart[pi];
+
+		/* Compute number of vertexes */
+		nv = ve-vs;
+
+		/* Allocate memory for a ring */
+		ring = (Ring*)malloc(sizeof(Ring));
+		ring->list = (Point*)malloc(sizeof(Point)*nv);
+		ring->n = nv;
+		ring->next = NULL;
+		ring->linked = 0;
+
+		/* Iterate over ring vertexes */
+		for ( vi=vs; vi<ve; vi++)
+		{
+			int vn = vi+1; /* next vertex for area */
+			if ( vn==ve ) vn = vs;
+
+			ring->list[vi-vs].x = obj->padfX[vi];
+			ring->list[vi-vs].y = obj->padfY[vi];
+			ring->list[vi-vs].z = obj->padfZ[vi];
+			ring->list[vi-vs].m = obj->padfM[vi];
+
+			area += (obj->padfX[vi] * obj->padfY[vn]) -
+			        (obj->padfY[vi] * obj->padfX[vn]);
+		}
+
+		/* Close the ring with first vertex  */
+		/*ring->list[vi].x = obj->padfX[vs]; */
+		/*ring->list[vi].y = obj->padfY[vs]; */
+		/*ring->list[vi].z = obj->padfZ[vs]; */
+		/*ring->list[vi].m = obj->padfM[vs]; */
+
+		/* Clockwise (or single-part). It's an Outer Ring ! */
+		if (area < 0.0 || obj->nParts ==1)
+		{
+			Outer[out_index] = ring;
+			out_index++;
+		}
+
+		/* Counterclockwise. It's an Inner Ring ! */
+		else
+		{
+			Inner[in_index] = ring;
+			in_index++;
+		}
+	}
+
+	LWDEBUGF(4, "FindPolygons[%d]: found %d Outer, %d Inners\n", call, out_index, in_index);
+
+	/* Put the inner rings into the list of the outer rings */
+	/* of which they are within */
+	for (pi=0; pi<in_index; pi++)
+	{
+		Point pt,pt2;
+		int i;
+		Ring *inner=Inner[pi], *outer=NULL;
+
+		pt.x = inner->list[0].x;
+		pt.y = inner->list[0].y;
+
+		pt2.x = inner->list[1].x;
+		pt2.y = inner->list[1].y;
+
+		for (i=0; i<out_index; i++)
+		{
+			int in;
+
+			in = PIP(pt, Outer[i]->list, Outer[i]->n);
+			if ( in || PIP(pt2, Outer[i]->list, Outer[i]->n) )
+			{
+				outer = Outer[i];
+				break;
+			}
+		}
+
+		if ( outer )
+		{
+			outer->linked++;
+			while (outer->next) outer = outer->next;
+			outer->next = inner;
+		}
+		else
+		{
+			/* The ring wasn't within any outer rings, */
+			/* assume it is a new outer ring. */
+			LWDEBUGF(4, "FindPolygons[%d]: hole %d is orphan\n", call, pi);
+
+			Outer[out_index] = inner;
+			out_index++;
+		}
+	}
+
+	*Out = Outer;
+	free(Inner);
+
+	return out_index;
+}
+
+void
+ReleasePolygons(Ring **polys, int npolys)
+{
+	int pi;
+	/* Release all memory */
+	for (pi=0; pi<npolys; pi++)
+	{
+		Ring *Poly, *temp;
+		Poly = polys[pi];
+		while (Poly != NULL)
+		{
+			temp = Poly;
+			Poly = Poly->next;
+			free(temp->list);
+			free(temp);
+		}
+	}
+	free(polys);
+}
+
+/*This function basically deals with the polygon case. */
+/*it sorts the polys in order of outer,inner,inner, so that inners */
+/*always come after outers they are within  */
+int
+InsertPolygon(void)
+{
+	Ring **Outer;
+	int polygon_total, ring_total;
+	int pi, vi; // part index and vertex index
+	int u;
+
+	LWCOLLECTION *lwcollection = NULL;
+
+	LWGEOM **lwpolygons;
+	uchar *serialized_lwgeom;
+	LWGEOM_UNPARSER_RESULT lwg_unparser_result;
+
+	LWPOLY *lwpoly;
+	DYNPTARRAY *dpas;
+	POINTARRAY ***pas;
+	POINT4D point4d;
+
+	int dims = 0, hasz = 0, hasm = 0;
+	int result;
+
+	/* Determine the correct dimensions: */
+	if (wkbtype & WKBZOFFSET) hasz = 1;
+	if (wkbtype & WKBMOFFSET) hasm = 1;
+	TYPE_SETZM(dims, hasz, hasm);
+
+	polygon_total = FindPolygons(obj, &Outer);
+
+	if (simple_geometries == 1 && polygon_total != 1) /* We write Non-MULTI geometries, but have several parts: */
+	{
+		pgis_logf("We have a Multipolygon with %d parts, can't use -S switch!", polygon_total);
+		return 0;
+	}
+
+	/* Allocate memory for our array of LWPOLYs */
+	lwpolygons = malloc(sizeof(LWPOLY *) * polygon_total);
+
+	/* Allocate memory for our POINTARRAY pointers for each polygon */
+	pas = malloc(sizeof(POINTARRAY **) * polygon_total);
+
+	/* Cycle through each individual polygon */
+	for (pi = 0; pi < polygon_total; pi++)
+	{
+		Ring *polyring;
+		int ring_index = 0;
+
+		/* Firstly count through the total number of rings in this polygon */
+		ring_total = 0;
+		polyring = Outer[pi];
+		while (polyring)
+		{
+			ring_total++;
+			polyring = polyring->next;
+		}
+
+		/* Reserve memory for the POINTARRAYs representing each ring */
+		pas[pi] = malloc(sizeof(POINTARRAY *) * ring_total);
+
+		/* Cycle through each ring within the polygon, starting with the outer */
+		polyring = Outer[pi];
+
+		while (polyring)
+		{
+			/* Create a DYNPTARRAY containing the points making up the ring */
+			dpas = dynptarray_create(polyring->n, dims);
+
+			for (vi = 0; vi < polyring->n; vi++)
+			{
+				/* Build up a point array of all the points in this ring */
+				point4d.x = polyring->list[vi].x;
+				point4d.y = polyring->list[vi].y;
+
+				if (wkbtype & WKBZOFFSET)
+					point4d.z = polyring->list[vi].z;
+				if (wkbtype & WKBMOFFSET)
+					point4d.m = polyring->list[vi].m;
+
+				dynptarray_addPoint4d(dpas, &point4d, 0);
+			}
+
+			/* Copy the POINTARRAY pointer from the DYNPTARRAY structure so we can
+			 use the LWPOLY constructor */
+			pas[pi][ring_index] = dpas->pa;
+
+			/* Free the DYNPTARRAY structure (we don't need this part anymore as we
+			have the reference to the internal POINTARRAY) */
+			lwfree(dpas);
+
+			polyring = polyring->next;
+			ring_index++;
+		}
+
+		/* Generate the LWGEOM */
+		lwpoly = lwpoly_construct(sr_id, NULL, ring_total, pas[pi]);
+		lwpolygons[pi] = lwpoly_as_lwgeom(lwpoly);
+	}
+
+	ReleasePolygons(Outer, polygon_total);
+
+	/* If using MULTIPOLYGONS then generate the serialized collection, otherwise just a single POLYGON */
+	if (simple_geometries == 0)
+	{
+		lwcollection = lwcollection_construct(MULTIPOLYGONTYPE, sr_id, NULL, polygon_total, lwpolygons);
+		serialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection));
+	}
+	else
+	{
+		serialized_lwgeom = lwgeom_serialize(lwpolygons[0]);
+	}
+
+	result = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL, -1);
+
+	if (result)
+	{
+		pgis_logf( "ERROR: %s", lwg_unparser_result.message);
+		return 0;
+	}
+
+	if ( ! OutputGeometry(lwg_unparser_result.wkoutput) ) return 0;
+
+	/* Free all of the allocated items */
+	lwfree(lwg_unparser_result.wkoutput);
+	lwfree(serialized_lwgeom);
+
+	/* Cycle through each polygon, freeing everything we need... */
+	for (u = 0; u < polygon_total; u++)
+		lwpoly_free(lwgeom_as_lwpoly(lwpolygons[u]));
+
+	/* Free the pointer arrays */
+	lwfree(pas);
+	lwfree(lwpolygons);
+	if (simple_geometries == 0)
+		lwfree(lwcollection);
+
+	return 1;
+}
+
+/*
+ * Insert either a POINT or MULTIPOINT into the output stream
+ */
+int
+InsertPoint(void)
+{
+	LWCOLLECTION *lwcollection;
+
+	LWGEOM **lwmultipoints;
+	uchar *serialized_lwgeom;
+	LWGEOM_UNPARSER_RESULT lwg_unparser_result;
+
+	DYNPTARRAY **dpas;
+	POINT4D point4d;
+
+	int dims = 0, hasz = 0, hasm = 0;
+	int result;
+	int u;
+
+	/* Determine the correct dimensions:  */
+	if (wkbtype & WKBZOFFSET) hasz = 1;
+	if (wkbtype & WKBMOFFSET) hasm = 1;
+	TYPE_SETZM(dims, hasz, hasm);
+
+	/* Allocate memory for our array of LWPOINTs and our dynptarrays */
+	lwmultipoints = malloc(sizeof(LWPOINT *) * obj->nVertices);
+	dpas = malloc(sizeof(DYNPTARRAY *) * obj->nVertices);
+
+	/* We need an array of pointers to each of our sub-geometries */
+	for (u = 0; u < obj->nVertices; u++)
+	{
+		/* Generate the point */
+		point4d.x = obj->padfX[u];
+		point4d.y = obj->padfY[u];
+
+		if (wkbtype & WKBZOFFSET)
+			point4d.z = obj->padfZ[u];
+		if (wkbtype & WKBMOFFSET)
+			point4d.m = obj->padfM[u];
+
+		/* Create a dynptarray containing a single point */
+		dpas[u] = dynptarray_create(1, dims);
+		dynptarray_addPoint4d(dpas[u], &point4d, 0);
+
+		/* Generate the LWPOINT */
+		lwmultipoints[u] = lwpoint_as_lwgeom(lwpoint_construct(sr_id, NULL, dpas[u]->pa));
+	}
+
+	/* If we have more than 1 vertex then we are working on a MULTIPOINT and so generate a MULTIPOINT
+	rather than a POINT */
+	if (obj->nVertices > 1)
+	{
+		lwcollection = lwcollection_construct(MULTIPOINTTYPE, sr_id, NULL, obj->nVertices, lwmultipoints);
+		serialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection));
+	}
+	else
+	{
+		serialized_lwgeom = lwgeom_serialize(lwmultipoints[0]);
+	}
+
+	result = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL, -1);
+
+	if (result)
+	{
+		pgis_logf("ERROR: %s", lwg_unparser_result.message);
+		return 0;
+	}
+
+	if ( ! OutputGeometry(lwg_unparser_result.wkoutput) ) return 0;
+
+	/* Free all of the allocated items */
+	lwfree(lwg_unparser_result.wkoutput);
+	lwfree(serialized_lwgeom);
+
+	for (u = 0; u < obj->nVertices; u++)
+	{
+		lwpoint_free(lwgeom_as_lwpoint(lwmultipoints[u]));
+		lwfree(dpas[u]);
+	}
+
+	lwfree(dpas);
+	lwfree(lwmultipoints);
+
+	return 1;
+}
+
+int
+OutputGeometry(char *geometry)
+{
+	if (!dump_format)
+		stringbuffer_append(sb_row, "'");
+
+	stringbuffer_aprintf(sb_row, "%s", geometry);
+
+	if (!dump_format)
+	{
+		stringbuffer_append(sb_row, "')");
+		if ( ! pgis_exec(stringbuffer_getstring(sb_row)) ) return 0;
+	}
+	else
+	{
+		stringbuffer_append_c(sb_row, '\n');
+		pgis_copy_write(stringbuffer_getstring(sb_row));
+	}
+	stringbuffer_clear(sb_row);
+	return 1;
+
+}
+
+
+
+void
+SetPgType(void)
+{
+	switch (shpfiletype)
+	{
+	case SHPT_POINT: /* Point */
+		pgtype = "POINT";
+		wkbtype = POINTTYPE;
+		pgdims = 2;
+		break;
+	case SHPT_ARC: /* PolyLine */
+		pgtype = "MULTILINESTRING";
+		wkbtype = MULTILINETYPE ;
+		pgdims = 2;
+		break;
+	case SHPT_POLYGON: /* Polygon */
+		pgtype = "MULTIPOLYGON";
+		wkbtype = MULTIPOLYGONTYPE;
+		pgdims = 2;
+		break;
+	case SHPT_MULTIPOINT: /* MultiPoint */
+		pgtype = "MULTIPOINT";
+		wkbtype = MULTIPOINTTYPE;
+		pgdims = 2;
+		break;
+	case SHPT_POINTM: /* PointM */
+		wkbtype = POINTTYPE | WKBMOFFSET;
+		pgtype = "POINTM";
+		pgdims = 3;
+		istypeM = 1;
+		break;
+	case SHPT_ARCM: /* PolyLineM */
+		wkbtype = MULTILINETYPE | WKBMOFFSET;
+		pgtype = "MULTILINESTRINGM";
+		pgdims = 3;
+		istypeM = 1;
+		break;
+	case SHPT_POLYGONM: /* PolygonM */
+		wkbtype = MULTIPOLYGONTYPE | WKBMOFFSET;
+		pgtype = "MULTIPOLYGONM";
+		pgdims = 3;
+		istypeM = 1;
+		break;
+	case SHPT_MULTIPOINTM: /* MultiPointM */
+		wkbtype = MULTIPOINTTYPE | WKBMOFFSET;
+		pgtype = "MULTIPOINTM";
+		pgdims = 3;
+		istypeM = 1;
+		break;
+	case SHPT_POINTZ: /* PointZ */
+		wkbtype = POINTTYPE | WKBMOFFSET | WKBZOFFSET;
+		pgtype = "POINT";
+		pgdims = 4;
+		break;
+	case SHPT_ARCZ: /* PolyLineZ */
+		pgtype = "MULTILINESTRING";
+		wkbtype = MULTILINETYPE | WKBZOFFSET | WKBMOFFSET;
+		pgdims = 4;
+		break;
+	case SHPT_POLYGONZ: /* MultiPolygonZ */
+		pgtype = "MULTIPOLYGON";
+		wkbtype = MULTIPOLYGONTYPE | WKBZOFFSET | WKBMOFFSET;
+		pgdims = 4;
+		break;
+	case SHPT_MULTIPOINTZ: /* MultiPointZ */
+		pgtype = "MULTIPOINT";
+		wkbtype = MULTIPOINTTYPE | WKBZOFFSET | WKBMOFFSET;
+		pgdims = 4;
+		break;
+	default:
+		pgtype = "GEOMETRY";
+		wkbtype = COLLECTIONTYPE | WKBZOFFSET | WKBMOFFSET;
+		pgdims = 4;
+		pgis_logf("Unknown geometry type: %d", shpfiletype);
+		break;
+	}
+
+	if (simple_geometries)
+	{
+		// adjust geometry name for CREATE TABLE by skipping MULTI
+		if ((wkbtype & 0x7) == MULTIPOLYGONTYPE) pgtype += 5;
+		if ((wkbtype & 0x7) == MULTILINETYPE) pgtype += 5;
+	}
+}
+
+int
+DropTable(char *schema, char *table, char *geom)
+{
+	/*---------------Drop the table--------------------------
+	 * TODO: if the table has more then one geometry column
+	 * the DROP TABLE call will leave spurious records in
+	 * geometry_columns. 
+	 *
+	 * If the geometry column in the table being dropped
+	 * does not match 'the_geom' or the name specified with
+	 * -g an error is returned by DropGeometryColumn. 
+	 *
+	 * The table to be dropped might not exist.
+	 *
+	 */
+	char *sql;
+
+	if ( schema )
+	{
+		if (readshape == 1)
+		{
+			asprintf(&sql, "SELECT DropGeometryColumn('%s','%s','%s')",	schema, table, geom);
+			if ( ! pgis_exec(sql) )
+			{
+				free(sql);
+				return 0;
+			}
+			free(sql);
+		}
+		asprintf(&sql, "DROP TABLE \"%s\".\"%s\"", schema, table);
+		if ( ! pgis_exec(sql) )
+		{
+			free(sql);
+			return 0;
+		}
+		free(sql);
+	}
+	else
+	{
+		if (readshape == 1)
+		{
+			asprintf(&sql, "SELECT DropGeometryColumn('','%s','%s')", table, geom);
+			if  ( ! pgis_exec(sql) )
+			{
+				free(sql);
+				return 0;
+			}
+			free(sql);
+		}
+		asprintf(&sql, "DROP TABLE \"%s\"", table);
+		if ( ! pgis_exec(sql) )
+		{
+			free(sql);
+			return 0;
+		}
+		free(sql);
+	}
+	return 1;
+}
+
+void
+GetFieldsSpec(void)
+{
+	/*
+	 * Shapefile (dbf) field name are at most 10chars + 1 NULL.
+	 * Postgresql field names are at most 63 bytes + 1 NULL.
+	 */
+#define MAXFIELDNAMELEN 64
+	int field_precision, field_width;
+	int j, z;
+	char  name[MAXFIELDNAMELEN];
+	char  name2[MAXFIELDNAMELEN];
+	DBFFieldType type = -1;
+#ifdef HAVE_ICONV
+	char *utf8str;
+#endif
+
+	num_fields = DBFGetFieldCount( hDBFHandle );
+	num_records = DBFGetRecordCount(hDBFHandle);
+	field_names = malloc(num_fields*sizeof(char*));
+	types = (DBFFieldType *)malloc(num_fields*sizeof(int));
+	widths = malloc(num_fields*sizeof(int));
+	precisions = malloc(num_fields*sizeof(int));
+	if (readshape == 1)
+	{
+		col_names = malloc((num_fields+2) * sizeof(char) * MAXFIELDNAMELEN);
+	}
+	{	//for dbf only, we do not need to allocate slot for the_geom
+		col_names = malloc((num_fields+1) * sizeof(char) * MAXFIELDNAMELEN);
+	}
+	strcpy(col_names, "(" );
+
+	/*fprintf(stderr, "Number of fields from DBF: %d\n", num_fields); */
+	for (j=0;j<num_fields;j++)
+	{
+		type = DBFGetFieldInfo(hDBFHandle, j, name, &field_width, &field_precision);
+
+		/*fprintf(stderr, "Field %d (%s) width/decimals: %d/%d\n", j, name, field_width, field_precision); */
+		types[j] = type;
+		widths[j] = field_width;
+		precisions[j] = field_precision;
+
+#ifdef HAVE_ICONV
+		if ( encoding )
+		{
+			utf8str = utf8(encoding, name);
+			if ( ! utf8str ) exit(1);
+			strcpy(name, utf8str);
+			free(utf8str);
+		}
+#endif
+
+
+		/*
+		 * Make field names lowercase unless asked to
+		 * keep identifiers case.
+		 */
+		if ( ! quoteidentifiers ) LowerCase(name);
+
+		/*
+		 * Escape names starting with the
+		 * escape char (_), those named 'gid'
+		 * or after pgsql reserved attribute names
+		 */
+		if ( name[0]=='_' ||
+		        ! strcmp(name,"gid") ||
+		        ! strcmp(name, "tableoid") ||
+		        ! strcmp(name, "cmax") ||
+		        ! strcmp(name, "xmax") ||
+		        ! strcmp(name, "cmin") ||
+		        ! strcmp(name, "primary") ||
+		        ! strcmp(name, "oid") ||
+		        ! strcmp(name, "ctid") )
+		{
+			strcpy(name2+2, name);
+			name2[0] = '_';
+			name2[1] = '_';
+			strcpy(name, name2);
+		}
+
+		/* Avoid duplicating field names */
+		for (z=0; z < j ; z++)
+		{
+			if (strcmp(field_names[z],name)==0)
+			{
+				strcat(name,"__");
+				sprintf(name+strlen(name),"%i",j);
+				break;
+			}
+		}
+
+		field_names[j] = malloc (strlen(name)+1);
+		strcpy(field_names[j], name);
+
+		/*sprintf(col_names, "%s\"%s\",", col_names, name);*/
+		strcat(col_names, "\"");
+		strcat(col_names, name);
+		if (readshape == 1 || j < (num_fields - 1))
+		{
+			//don't include last comma if its the last field and no geometry field will follow
+			strcat(col_names, "\",");
+		}
+		else
+		{
+			strcat(col_names, "\"");
+		}
+	}
+	/*sprintf(col_names, "%s\"%s\")", col_names, geom);*/
+	if (readshape == 1)
+	{
+		strcat(col_names, geom);
+	}
+	strcat(col_names, ")");
+}
+
+#ifdef HAVE_ICONV
+
+char *
+utf8 (const char *fromcode, char *inputbuf)
+{
+	iconv_t cd;
+	char *outputptr;
+	char *outputbuf;
+	size_t outbytesleft;
+	size_t inbytesleft;
+
+	inbytesleft = strlen (inputbuf);
+
+	cd = iconv_open ("UTF-8", fromcode);
+	if (cd == (iconv_t) - 1)
+	{
+		pgis_logf("utf8: iconv_open: %s", strerror (errno));
+		return NULL;
+	}
+
+	outbytesleft = inbytesleft*3+1; /* UTF8 string can be 3 times larger */
+	/* then local string */
+	outputbuf = (char *) malloc (outbytesleft);
+	if (!outputbuf)
+	{
+		pgis_logf("utf8: malloc: %s", strerror (errno));
+		return NULL;
+	}
+	memset (outputbuf, 0, outbytesleft);
+	outputptr = outputbuf;
+
+	if (-1==iconv(cd, &inputbuf, &inbytesleft, &outputptr, &outbytesleft))
+	{
+		pgis_logf("utf8: %s", strerror (errno));
+		return NULL;
+	}
+
+	iconv_close (cd);
+
+	return outputbuf;
+}
+
+#endif /* defined HAVE_ICONV */
+
+/**********************************************************************
+ * $Log$
+ * Revision 1.109  2008/04/09 14:12:17  robe
+ *         - Added support to load dbf-only files
+ *
+ * Revision 1.108  2006/06/16 14:12:17  strk
+ *         - BUGFIX in pgsql2shp successful return code.
+ *         - BUGFIX in shp2pgsql handling of MultiLine WKT.
+ *
+ * Revision 1.107  2006/04/18 09:16:26  strk
+ * Substituted bzero() use with memset()
+ *
+ * Revision 1.106  2006/01/16 10:42:58  strk
+ * Added support for Bool and Date DBF<=>PGIS mapping
+ *
+ * Revision 1.105  2006/01/09 16:40:16  strk
+ * ISO C90 comments, signedness mismatch fixes
+ *
+ * Revision 1.104  2005/11/01 09:25:47  strk
+ * Reworked NULL geometries handling code letting user specify policy (insert,skip,abort). Insert is the default.
+ *
+ * Revision 1.103  2005/10/24 15:54:22  strk
+ * fixed wrong assumption about maximum size of integer attributes (width is maximum size of text representation)
+ *
+ * Revision 1.102  2005/10/24 11:30:59  strk
+ *
+ * Fixed a bug in string attributes handling truncating values of maximum
+ * allowed length, curtesy of Lars Roessiger.
+ * Reworked integer attributes handling to be stricter in dbf->sql mapping
+ * and to allow for big int8 values in sql->dbf conversion
+ *
+ * Revision 1.101  2005/10/21 11:33:55  strk
+ * Applied patch by Lars Roessiger handling numerical values with a trailing decima
+ * l dot
+ *
+ * Revision 1.100  2005/10/13 13:40:20  strk
+ * Fixed return code from shp2pgsql
+ *
+ * Revision 1.99  2005/10/03 18:08:55  strk
+ * Stricter string attributes lenght handling. DBF header will be used
+ * to set varchar maxlenght, (var)char typmod will be used to set DBF header
+ * len.
+ *
+ * Revision 1.98  2005/10/03 07:45:58  strk
+ * Issued a warning when -W is specified and no UTF8 support has been compiled in.
+ *
+ * Revision 1.97  2005/09/30 08:59:29  strk
+ * Fixed release of stack memory occurring when shp2pgsql is compiled with USE_ICONV defined, an attribute value needs to be escaped and no -W is used
+ *
+ * Revision 1.96  2005/08/29 22:36:25  strk
+ * Removed premature object destruction in InsertLineString{WKT,} causing segfault
+ *
+ * Revision 1.95  2005/08/29 11:48:33  strk
+ * Fixed sprintf() calls to avoid overlapping memory,
+ * reworked not-null objects existance check to reduce startup costs.
+ *
+ * Revision 1.94  2005/07/27 02:47:14  strk
+ * Support for multibyte field names in loader
+ *
+ * Revision 1.93  2005/07/27 02:35:50  strk
+ * Minor cleanups in loader
+ *
+ * Revision 1.92  2005/07/27 02:07:01  strk
+ * Fixed handling of POINT types as WKT (-w) in loader
+ *
+ * Revision 1.91  2005/07/04 09:47:03  strk
+ * Added conservative iconv detection code
+ *
+ * Revision 1.90  2005/06/16 17:55:58  strk
+ * Added -I switch for GiST index creation in loader
+ *
+ * Revision 1.89  2005/04/21 09:08:34  strk
+ * Applied patch from Ron Mayer fixing a segfault in string escaper funx
+ *
+ * Revision 1.88  2005/04/14 12:58:59  strk
+ * Applied patch by Gino Lucrezi fixing bug in string escaping code.
+ *
+ * Revision 1.87  2005/04/06 14:16:43  strk
+ * Removed manual update of gid field.
+ *
+ * Revision 1.86  2005/04/06 14:02:08  mschaber
+ * added -p option (prepare mode) that spits out the table schema without
+ * inserting any data.
+ *
+ * Revision 1.85  2005/04/06 10:46:10  strk
+ * Bugfix in -w (hwgeom) handling of ZM shapefiles.
+ * Big reorganizzation of code to easy maintainance.
+ *
+ * Revision 1.84  2005/04/04 20:51:26  strk
+ * Added -w flag to output old (WKT/HWGEOM) sql.
+ *
+ * Revision 1.83  2005/03/15 12:24:40  strk
+ * hole-in-ring detector made more readable
+ *
+ * Revision 1.82  2005/03/14 22:02:31  strk
+ * Fixed holes handling.
+ *
+ * Revision 1.81  2005/03/08 11:06:33  strk
+ * modernized old-style parameter declarations
+ *
+ * Revision 1.80  2005/03/04 14:48:22  strk
+ * Applied patch from Jonne Savolainen fixing multilines handling
+ *
+ * Revision 1.79  2005/01/31 22:15:22  strk
+ * Added maintainer notice, to reduce Jeff-strk mail bounces
+ *
+ * Revision 1.78  2005/01/17 09:21:13  strk
+ * Added one more bytes for terminating NULL in utf8 encoder
+ *
+ * Revision 1.77  2005/01/16 16:50:01  strk
+ * String escaping algorithm made simpler and more robust.
+ * Removed escaped strings leaking.
+ * Fixed UTF8 encoder to allocate enough space for 3bytes chars strings.
+ *
+ * Revision 1.76  2005/01/12 17:03:20  strk
+ * Added optional UTF8 output support as suggested by IIDA Tetsushi
+ *
+ * Revision 1.75  2004/11/15 10:51:35  strk
+ * Fixed a bug in PIP invocation, added some debugging lines.
+ *
+ * Revision 1.74  2004/10/17 13:25:44  strk
+ * removed USE_WKB partially-used define
+ *
+ * Revision 1.73  2004/10/17 13:24:44  strk
+ * HEXWKB polygon
+ *
+ * Revision 1.72  2004/10/17 12:59:12  strk
+ * HEXWKB multiline output
+ *
+ * Revision 1.71  2004/10/17 12:26:02  strk
+ * Point and MultiPoint loaded using HEXWKB.
+ *
+ * Revision 1.70  2004/10/15 22:01:35  strk
+ * Initial WKB functionalities
+ *
+ * Revision 1.69  2004/10/07 21:52:28  strk
+ * Lots of rewriting/cleanup. TypeM/TypeZ supports.
+ *
+ * Revision 1.68  2004/10/07 06:54:24  strk
+ * cleanups
+ *
+ * Revision 1.67  2004/10/06 10:11:16  strk
+ * Other separator fixes
+ *
+ * Revision 1.66  2004/10/06 09:40:27  strk
+ * Handled 0-DBF-attributes corner case.
+ *
+ * Revision 1.65  2004/09/20 17:13:31  strk
+ * changed comments to better show shape type handling
+ *
+ * Revision 1.64  2004/08/20 08:14:37  strk
+ * Whole output wrapped in transaction blocks.
+ * Drops are out of transaction, and multiple transactions are used
+ * for INSERT mode.
+ *
+ **********************************************************************/

Added: trunk/loader/shp2pgsql-core.h
===================================================================
--- trunk/loader/shp2pgsql-core.h	2009-01-16 17:58:39 UTC (rev 3537)
+++ trunk/loader/shp2pgsql-core.h	2009-01-19 21:33:14 UTC (rev 3538)
@@ -0,0 +1,70 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "shapefil.h"
+#include "getopt.h"
+
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#endif
+
+#include "../liblwgeom/liblwgeom.h"
+#include "stringbuffer.h"
+
+#define RCSID "$Id: shp2pgsql.c 3450 2008-12-18 20:42:09Z pramsey $"
+
+enum {
+	insert_null,
+	skip_null,
+	abort_on_null
+};
+
+/*
+** Global variables for Core
+*/
+extern char opt; /* load mode: c = create, d = delete, a = append, p = prepare */
+extern char *table; /* table to load into */
+extern char *schema; /* schema to load into */
+extern char *geom; /* geometry column name to use */
+extern char *shp_file; /* the shape file (without the .shp extension) */
+extern int dump_format; /* 0 = SQL inserts, 1 = dump */
+extern int simple_geometries; /* 0 = MULTIPOLYGON/MULTILINESTRING, 1 = force to POLYGON/LINESTRING */
+extern int quoteidentifiers; /* 0 = columnname, 1 = "columnName" */
+extern int forceint4; /* 0 = allow int8 fields, 1 = no int8 fields */
+extern int createindex; /* 0 = no index, 1 = create index after load */
+extern int readshape; /* 0 = load DBF file only, 1 = load everything */
+#ifdef HAVE_ICONV
+extern char *encoding; /* iconv encoding name */
+#endif
+extern int null_policy; /* how to handle nulls */
+extern int sr_id; /* SRID specified */
+extern int gui_mode; /* 1 = GUI, 0 = commandline */
+extern int translation_stage; /* 1 = ready, 2 = done start, 3 = done middle, 4 = done end */
+extern int cur_entity; /* what record are we working on? */
+
+
+/*
+** Global variables used only by GUI
+*/
+
+/*
+** Prototypes across modules
+*/
+extern int translation_start(void); 
+extern int translation_middle(void); 
+extern int translation_end(void); 
+extern void pgui_log_va(const char *fmt, va_list ap);
+extern int pgui_exec(const char *sql);
+extern int pgui_copy_write(const char *line);
+extern int pgui_copy_start(const char *sql);
+extern int pgui_copy_end(const int rollback);
+extern void LowerCase(char *s);
+

Added: trunk/loader/shp2pgsql-gui.c
===================================================================
--- trunk/loader/shp2pgsql-gui.c	2009-01-16 17:58:39 UTC (rev 3537)
+++ trunk/loader/shp2pgsql-gui.c	2009-01-19 21:33:14 UTC (rev 3538)
@@ -0,0 +1,905 @@
+/**********************************************************************
+ * $Id: shp2pgsql-gui.c 3450 2008-12-18 20:42:09Z pramsey $
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2008 OpenGeo.org
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ * Maintainer: Paul Ramsey <pramsey at opengeo.org>
+ *
+ **********************************************************************/
+
+#define _GNU_SOURCE
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include "libpq-fe.h"
+#include "shp2pgsql-core.h"
+
+/*
+** Global variables for GUI only
+*/
+
+/* Main window */
+static GtkWidget *window_main;
+static GtkWidget *entry_pg_user;
+static GtkWidget *entry_pg_pass;
+static GtkWidget *entry_pg_host;
+static GtkWidget *entry_pg_port;
+static GtkWidget *entry_pg_db;
+static GtkWidget *entry_config_table;
+static GtkWidget *entry_config_schema;
+static GtkWidget *entry_config_srid;
+static GtkWidget *entry_config_geocolumn;
+static GtkWidget *label_pg_connection_test;
+static GtkWidget *textview_log;
+static GtkWidget *file_chooser_button_shape;
+static GtkTextBuffer *textbuffer_log;
+
+/* Options window */
+static GtkWidget *window_options;
+static GtkWidget *entry_options_encoding;	
+static GtkWidget *entry_options_nullpolicy;	
+static GtkWidget *checkbutton_options_preservecase;
+static GtkWidget *checkbutton_options_forceint;
+static GtkWidget *checkbutton_options_autoindex;
+static GtkWidget *checkbutton_options_dbfonly;
+
+/* Other */
+static char *pgui_errmsg = NULL;
+static PGconn *pg_connection;
+
+
+/*
+** Write a message to the Import Log text area.
+*/
+static void
+pgui_logf(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+
+	pgui_log_va(fmt, ap);
+
+	va_end(ap);
+	return;
+}
+
+/*
+** Write a message to the Import Log text area.
+*/
+void
+pgui_log_va(const char *fmt, va_list ap)
+{
+	char *msg;
+
+	if (!vasprintf (&msg, fmt, ap)) return;
+
+	gtk_text_buffer_insert_at_cursor(textbuffer_log, msg, -1);
+	gtk_text_buffer_insert_at_cursor(textbuffer_log, "\n", -1);
+	gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(textview_log), gtk_text_buffer_get_insert(textbuffer_log) );
+
+	free(msg);
+	return;
+}
+
+static void
+pgui_seterr(const char *errmsg)
+{
+	if ( pgui_errmsg )
+	{
+		free(pgui_errmsg);
+	}
+	pgui_errmsg = strdup(errmsg);
+	return;
+}
+
+
+
+/*
+** Run a SQL command against the current connection.
+*/
+int
+pgui_exec(const char *sql)
+{
+	PGresult *res = NULL;
+	ExecStatusType status;
+
+	/* We need a connection to do anything. */
+	if ( ! pg_connection ) return 0;
+	if ( ! sql ) return 0;
+
+	res = PQexec(pg_connection, sql);
+	status = PQresultStatus(res);
+	PQclear(res);
+
+	/* Did something unexpected happen? */
+	if ( ! ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) )
+	{
+		/* Log notices and return success. */
+		if ( status == PGRES_NONFATAL_ERROR )
+		{
+			pgui_logf("%s", PQerrorMessage(pg_connection));
+			return 1;
+		}
+
+		/* Log errors and return failure. */
+		pgui_logf("Failed record number #%d", cur_entity);
+		pgui_logf("Failed SQL was: %s", sql);
+		pgui_logf("Failed in pgui_exec(): %s", PQerrorMessage(pg_connection));
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+** Start the COPY process.
+*/
+int
+pgui_copy_start(const char *sql)
+{
+	PGresult *res = NULL;
+	ExecStatusType status;
+
+	/* We need a connection to do anything. */
+	if ( ! pg_connection ) return 0;
+	if ( ! sql ) return 0;
+
+	res = PQexec(pg_connection, sql);
+	status = PQresultStatus(res);
+	PQclear(res);
+
+	/* Did something unexpected happen? */
+	if ( status != PGRES_COPY_IN )
+	{
+		/* Log errors and return failure. */
+		pgui_logf("Failed SQL was: %s", sql);
+		pgui_logf("Failed in pgui_copy_start(): %s", PQerrorMessage(pg_connection));
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+** Send a line (row) of data into the COPY procedure.
+*/
+int
+pgui_copy_write(const char *line)
+{
+
+	/* We need a connection to do anything. */
+	if ( ! pg_connection ) return 0;
+	if ( ! line ) return 0;
+
+	/* Did something unexpected happen? */
+	if ( PQputCopyData(pg_connection, line, strlen(line)) < 0 )
+	{
+		/* Log errors and return failure. */
+		pgui_logf("Failed record number #%d", cur_entity);
+		pgui_logf("Failed row was: %s", line);
+		pgui_logf("Failed in pgui_copy_write(): %s", PQerrorMessage(pg_connection));
+		return 0;
+	}
+
+	return 1;
+
+}
+
+/*
+** Finish the COPY process.
+*/
+int
+pgui_copy_end(const int rollback)
+{
+	char *errmsg = NULL;
+
+	/* We need a connection to do anything. */
+	if ( ! pg_connection ) return 0;
+
+	if ( rollback ) errmsg = "Roll back the copy.";
+
+	/* Did something unexpected happen? */
+	if ( PQputCopyEnd(pg_connection, errmsg) < 0 )
+	{
+		/* Log errors and return failure. */
+		pgui_logf("Failed in pgui_copy_end(): %s", PQerrorMessage(pg_connection));
+		return 0;
+	}
+
+	return 1;
+}
+
+static gboolean
+check_translation_stage (gpointer data)
+{
+	int rv = 0;
+	if ( translation_stage == 0 ) return FALSE;
+	if ( translation_stage == 4 )
+	{
+		pgui_logf("Import complete.");
+		return FALSE;
+	}
+	if ( translation_stage == 1 )
+	{
+		rv = translation_start();
+		if ( ! rv )
+		{
+			pgui_logf("Import failed.");
+			translation_stage = 0;
+		}
+		return TRUE;
+	}
+	if ( translation_stage == 2 )
+	{
+		rv = translation_middle();
+		if ( ! rv )
+		{
+			pgui_logf("Import failed.");
+			translation_stage = 0;
+		}
+		return TRUE;
+	}
+	if ( translation_stage == 3 )
+	{
+		rv = translation_end();
+		if ( ! rv )
+		{
+			pgui_logf("Import failed.");
+			translation_stage = 0;
+		}
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/* Terminate the main loop and exit the application. */
+static void
+pgui_quit (GtkWidget *widget, gpointer data)
+{
+	if ( pg_connection) PQfinish(pg_connection);
+	pg_connection = NULL;
+	gtk_main_quit ();
+}
+
+static char *
+pgui_read_connection(void)
+{
+	const char *pg_host = gtk_entry_get_text(GTK_ENTRY(entry_pg_host));
+	const char *pg_port = gtk_entry_get_text(GTK_ENTRY(entry_pg_port));
+	const char *pg_user = gtk_entry_get_text(GTK_ENTRY(entry_pg_user));
+	const char *pg_pass = gtk_entry_get_text(GTK_ENTRY(entry_pg_pass));
+	const char *pg_db = gtk_entry_get_text(GTK_ENTRY(entry_pg_db));
+	char *connection_string = NULL;
+
+	if ( ! pg_host || strlen(pg_host) == 0 )
+	{
+		pgui_seterr("Fill in the server host.");
+		return NULL;
+	}
+	if ( ! pg_port || strlen(pg_port) == 0 )
+	{
+		pgui_seterr("Fill in the server port.");
+		return NULL;
+	}
+	if ( ! pg_user || strlen(pg_user) == 0 )
+	{
+		pgui_seterr("Fill in the user name.");
+		return NULL;
+	}
+	if ( ! pg_db || strlen(pg_db) == 0 )
+	{
+		pgui_seterr("Fill in the database name.");
+		return NULL;
+	}
+	if ( ! atoi(pg_port) )
+	{
+		pgui_seterr("Server port must be a number.");
+		return NULL;
+	}
+	if ( ! asprintf(&connection_string, "user=%s password=%s port=%s host=%s dbname=%s", pg_user, pg_pass, pg_port, pg_host, pg_db) )
+	{
+		return NULL;
+	}
+	if ( connection_string )
+	{
+		return connection_string;
+	}
+	return NULL;
+}
+
+static char *
+pgui_read_destination(void)
+{
+	const char *pg_table = gtk_entry_get_text(GTK_ENTRY(entry_config_table));
+	const char *pg_schema = gtk_entry_get_text(GTK_ENTRY(entry_config_schema));
+	const char *pg_geom = gtk_entry_get_text(GTK_ENTRY(entry_config_geocolumn));
+	
+	char *dest_string = NULL;
+
+	if ( ! pg_table || strlen(pg_table) == 0 )
+	{
+		pgui_seterr("Fill in the destination table.");
+		return NULL;
+	}
+	if ( ! pg_schema || strlen(pg_schema) == 0 )
+	{
+		pg_schema = "public";
+	}
+	if ( ! pg_geom || strlen(pg_geom) == 0 )
+	{
+		pg_geom = "the_geom";
+	}
+
+	if ( ! asprintf(&dest_string, "%s.%s", pg_schema, pg_table) )
+	{
+		return NULL;
+	}
+
+	if ( dest_string )
+	{
+		/* Set the schema and table into the globals. */
+		/* TODO change the core code to use dest_string instead */
+		/* and move the global set into the import function. */
+		table = strdup(pg_table);
+		schema = strdup(pg_schema);
+		geom = strdup(pg_geom);
+		return dest_string;
+	}
+	return NULL;
+}
+
+static void
+pgui_raise_error_dialogue(void)
+{
+	GtkWidget *dialog, *label;
+	gint result;
+
+	label = gtk_label_new(pgui_errmsg);
+	dialog = gtk_dialog_new_with_buttons("Error", GTK_WINDOW(window_main), 
+	                GTK_DIALOG_MODAL & GTK_DIALOG_NO_SEPARATOR & GTK_DIALOG_DESTROY_WITH_PARENT, 
+	                GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+	gtk_dialog_set_has_separator ( GTK_DIALOG(dialog), FALSE );
+	gtk_container_set_border_width (GTK_CONTAINER(dialog), 5);
+	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 15);
+	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
+	gtk_widget_show_all (dialog);
+	result = gtk_dialog_run(GTK_DIALOG(dialog));
+	gtk_widget_destroy(dialog);
+	return;
+}
+
+static void
+pgui_action_import(GtkWidget *widget, gpointer data)
+{
+	char *connection_string = NULL;
+	char *dest_string = NULL;
+	char *source_file = NULL;
+	
+	const char *entry_srid = gtk_entry_get_text(GTK_ENTRY(entry_config_srid));
+	const char *entry_encoding = gtk_entry_get_text(GTK_ENTRY(entry_options_encoding));
+
+	/* Do nothing if we're busy */
+	if ( translation_stage > 0 && translation_stage < 4 )
+	{
+		return;
+	}
+
+	if ( ! (connection_string = pgui_read_connection() ) )
+	{
+		pgui_raise_error_dialogue();
+		return;
+	}
+
+	if ( ! (dest_string = pgui_read_destination() ) )
+	{
+		pgui_raise_error_dialogue();
+		return;
+	}
+
+	if ( ! (source_file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser_button_shape))) )
+	{
+		pgui_seterr("Select a shape file to import.");
+		pgui_raise_error_dialogue();
+		return;
+	}
+
+	/* Log what we know so far */
+	pgui_logf("Connection: %s", connection_string);
+	pgui_logf("Destination: %s", dest_string);
+	pgui_logf("Source File: %s", source_file);
+
+	/* Set the shape file into the global. */
+	shp_file = strdup(source_file);
+	g_free(source_file);
+
+	/* Set the mode to "create" in the global. */
+	opt = 'c';
+
+	/* Set the output mode to inserts. */
+	dump_format = 0;
+
+	/* 
+	** Read the options from the options dialogue... 
+	*/
+	
+	/* Encoding */
+	if( entry_encoding && strlen(entry_encoding) > 0 ) 
+	{
+		encoding = strdup(entry_encoding);
+	}
+	
+	/* SRID */
+	if ( ! ( sr_id = atoi(entry_srid) ) ) 
+	{
+		sr_id = -1;
+	}
+
+	/* Preserve case */
+	if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_preservecase)) )
+		quoteidentifiers = 1;
+	else
+		quoteidentifiers = 0;
+
+	/* No long integers in table */
+	if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_forceint)) )
+		forceint4 = 1;
+	else
+		forceint4 = 0;
+	
+	/* Create spatial index after load */
+	if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_autoindex)) )
+		createindex = 1;
+	else
+		createindex = 0;
+	
+	/* Read the .shp file, don't ignore it */
+	if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_options_dbfonly)) )
+		readshape = 0;
+	else
+		readshape = 1;
+
+	/* Connect to the database. */
+	if ( pg_connection ) PQfinish(pg_connection);
+	pg_connection = PQconnectdb(connection_string);
+
+	if (PQstatus(pg_connection) == CONNECTION_BAD)
+	{
+		pgui_logf( "Connection failed: %s", PQerrorMessage(pg_connection));
+		gtk_label_set_text(GTK_LABEL(label_pg_connection_test), "Connection failed.");
+		free(connection_string);
+		free(dest_string);
+		PQfinish(pg_connection);
+		pg_connection = NULL;
+		return;
+	}
+
+	/* add the idle action */
+	cur_entity = -1;
+	translation_stage = 1;
+	g_idle_add(check_translation_stage, NULL);
+
+	free(connection_string);
+	free(dest_string);
+
+	return;
+
+}
+
+static void
+pgui_action_options(GtkWidget *widget, gpointer data)
+{
+	/* Do nothing if we're busy */
+	if ( translation_stage > 0 && translation_stage < 4 )
+	{
+		return;
+	}
+	/* TODO Open the options dialog window here... */
+	pgui_logf("Open the options dialog...");
+	gtk_widget_show_all (window_options);
+	return;
+}
+
+static void
+pgui_action_cancel(GtkWidget *widget, gpointer data)
+{
+	if ( translation_stage > 0 && translation_stage < 4 )
+	{
+		pgui_logf("Import stopped.");
+
+		translation_stage = 0; /* return to idle if we are running */
+	}
+	else
+	{
+		pgui_quit(widget, data); /* quit if we're not running */
+	}
+	return;
+}
+
+static void
+pgui_action_connection_test(GtkWidget *widget, gpointer data)
+{
+	char *connection_string = NULL;
+
+	/* Do nothing if we're busy */
+	if ( translation_stage > 0 && translation_stage < 4 )
+	{
+		return;
+	}
+
+
+	if ( ! (connection_string = pgui_read_connection()) )
+	{
+		pgui_raise_error_dialogue();
+		return;
+	}
+	pgui_logf("Connecting: %s", connection_string);
+
+	if ( pg_connection )
+		PQfinish(pg_connection);
+
+	pg_connection = PQconnectdb(connection_string);
+	if (PQstatus(pg_connection) == CONNECTION_BAD)
+	{
+		pgui_logf( "Connection failed: %s", PQerrorMessage(pg_connection));
+		gtk_label_set_text(GTK_LABEL(label_pg_connection_test), "Connection failed.");
+		free(connection_string);
+		PQfinish(pg_connection);
+		pg_connection = NULL;
+		return;
+	}
+	gtk_label_set_text(GTK_LABEL(label_pg_connection_test), "Connection succeeded.");
+	pgui_logf( "Connection succeeded." );
+	gtk_widget_show(label_pg_connection_test);
+	PQfinish(pg_connection);
+	pg_connection = NULL;
+	free(connection_string);
+
+	return;
+}
+
+static void
+pgui_action_close_options(GtkWidget *widget, gpointer data)
+{
+	gtk_widget_hide_all (window_options);
+	return;
+}
+
+static void
+pgui_action_shape_file_set(GtkWidget *widget, gpointer data)
+{
+	char *shp_file;
+	int shp_file_len;
+	char *table_start;
+	char *table_end;
+	char *table;
+	
+	shp_file = strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)));
+	shp_file_len = strlen(shp_file);
+
+	/* Roll back from end to first slash character. */
+	table_start = shp_file + shp_file_len;
+	while( *table_start != '/' && *table_start != '\\' && table_start > shp_file) {
+		table_start--;
+	}
+	table_start++; /* Forward one to start of actual characters. */
+
+	/* Roll back from end to first . character. */
+	table_end = shp_file + shp_file_len;
+	while( *table_end != '.' && table_end > shp_file && table_end > table_start ) {
+		table_end--;
+	}
+	
+	/* Copy the table name into a fresh memory slot. */
+	table = lwalloc(table_end - table_start + 1);
+	memcpy(table, table_start, table_end - table_start);
+	table[table_end - table_start + 1] = '\0';
+
+	/* Set the table name into the entry. */
+	gtk_entry_set_text(GTK_ENTRY(entry_config_table), table);
+	
+	lwfree(shp_file);
+}
+
+static void
+pgui_create_options_dialogue_add_label(GtkWidget *table, const char *str, gfloat alignment, int row)
+{
+	GtkWidget *align = gtk_alignment_new( alignment, 0.5, 0.0, 1.0 );
+	GtkWidget *label = gtk_label_new( str );
+	gtk_table_attach_defaults(GTK_TABLE(table), align, 1, 3, row, row+1 );
+	gtk_container_add (GTK_CONTAINER (align), label);
+}
+
+static void
+pgui_create_options_dialogue()
+{
+	GtkWidget *table_options;
+	GtkWidget *button_options_ok;
+	GtkWidget *vbox_options;
+	GtkWidget *align_options_center;
+	static int text_width = 12;
+	
+	window_options = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_modal (GTK_WINDOW(window_options), TRUE);
+	gtk_window_set_keep_above (GTK_WINDOW(window_options), TRUE);
+	gtk_window_set_title (GTK_WINDOW(window_options), "Import Options");
+	gtk_window_set_default_size (GTK_WINDOW(window_options), 180, 200);
+
+	table_options = gtk_table_new(7, 3, TRUE);
+	gtk_container_set_border_width (GTK_CONTAINER (table_options), 12);
+	gtk_table_set_row_spacings(GTK_TABLE(table_options), 5);
+	gtk_table_set_col_spacings(GTK_TABLE(table_options), 10);
+
+	pgui_create_options_dialogue_add_label(table_options, "DBF file character encoding", 0.0, 0);
+	entry_options_encoding = gtk_entry_new();
+	gtk_entry_set_width_chars(GTK_ENTRY(entry_options_encoding), text_width);
+	gtk_entry_set_text(GTK_ENTRY(entry_options_encoding), "LATIN1");
+	gtk_table_attach_defaults(GTK_TABLE(table_options), entry_options_encoding, 0, 1, 0, 1 );
+	
+	pgui_create_options_dialogue_add_label(table_options, "Preserve case of column names", 0.0, 1);
+	checkbutton_options_preservecase = gtk_check_button_new();
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_preservecase), FALSE);
+	align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 );
+	gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 1, 2 );
+	gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_preservecase);
+	
+	pgui_create_options_dialogue_add_label(table_options, "Do not create 'bigint' columns", 0.0, 2);
+	checkbutton_options_forceint = gtk_check_button_new();
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_forceint), TRUE);
+	align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 );
+	gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 2, 3 );
+	gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_forceint);
+
+	pgui_create_options_dialogue_add_label(table_options, "Create spatial index automatically after load", 0.0, 3);
+	checkbutton_options_autoindex = gtk_check_button_new();
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_options_autoindex), TRUE);
+	align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 );
+	gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 3, 4 );
+	gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_autoindex);
+
+	pgui_create_options_dialogue_add_label(table_options, "Load only attribute (dbf) data", 0.0, 4);
+	checkbutton_options_dbfonly = gtk_check_button_new();
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON	(checkbutton_options_dbfonly), FALSE);
+	align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 0.0 );
+	gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 4, 5 );
+	gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_options_dbfonly);
+
+	pgui_create_options_dialogue_add_label(table_options, "Policy for records with empty (null) shapes", 0.0, 5);
+	entry_options_nullpolicy = gtk_entry_new();
+	gtk_entry_set_width_chars(GTK_ENTRY(entry_options_nullpolicy), text_width);
+	gtk_entry_set_text(GTK_ENTRY(entry_options_nullpolicy), "0");
+	gtk_table_attach_defaults(GTK_TABLE(table_options), entry_options_nullpolicy, 0, 1, 5, 6 );
+	
+	button_options_ok = gtk_button_new_with_label("OK");
+	g_signal_connect (G_OBJECT (button_options_ok), "clicked", G_CALLBACK (pgui_action_close_options), NULL);
+	gtk_table_attach_defaults(GTK_TABLE(table_options), button_options_ok, 1, 2, 6, 7 );
+
+	vbox_options = gtk_vbox_new(FALSE, 10);
+	gtk_box_pack_start(GTK_BOX(vbox_options), table_options, FALSE, FALSE, 0);
+	gtk_container_add (GTK_CONTAINER (window_options), vbox_options);
+
+
+}
+
+static void
+pgui_create_main_window(void)
+{
+	static int text_width = 12;
+	/* Reusable label handle */
+	GtkWidget *label;
+	/* Main widgets */
+	GtkWidget *vbox_main;
+	/* Shape file section */
+	GtkWidget *file_chooser_dialog_shape;
+	GtkFileFilter *file_filter_shape;
+	/* PgSQL section */
+	GtkWidget *frame_pg, *frame_shape, *frame_log, *frame_config;
+	GtkWidget *table_pg, *table_config;
+	GtkWidget *button_pg_test;
+	/* Button section */
+	GtkWidget *hbox_buttons, *button_options, *button_import, *button_cancel;
+	/* Log section */
+	GtkWidget *scrolledwindow_log;
+
+	/* create the main, top level, window */
+	window_main = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+	/* give the window a 10px wide border */
+	gtk_container_set_border_width (GTK_CONTAINER (window_main), 10);
+
+	/* give it the title */
+	gtk_window_set_title (GTK_WINDOW (window_main), "Shape File to PostGIS Importer");
+
+	/* open it a bit wider so that both the label and title show up */
+	gtk_window_set_default_size (GTK_WINDOW (window_main), 180, 500);
+
+	/* Connect the destroy event of the window with our pgui_quit function
+	*  When the window is about to be destroyed we get a notificaiton and
+	*  stop the main GTK loop
+	*/
+	g_signal_connect (G_OBJECT (window_main), "destroy", G_CALLBACK (pgui_quit), NULL);
+
+	/*
+	** Shape file selector 
+	*/
+	frame_shape = gtk_frame_new("Shape File");
+	gtk_container_set_border_width (GTK_CONTAINER (frame_shape), 0);
+	file_chooser_dialog_shape = gtk_file_chooser_dialog_new( "Select a Shape File", GTK_WINDOW (window_main), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
+	file_chooser_button_shape = gtk_file_chooser_button_new_with_dialog( file_chooser_dialog_shape );
+	gtk_container_set_border_width (GTK_CONTAINER (file_chooser_button_shape), 8);
+	file_filter_shape = gtk_file_filter_new();
+	gtk_file_filter_add_pattern(GTK_FILE_FILTER(file_filter_shape), "*.shp");
+	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser_button_shape), file_filter_shape);
+	gtk_container_add (GTK_CONTAINER (frame_shape), file_chooser_button_shape);
+	g_signal_connect (G_OBJECT (file_chooser_button_shape), "file-set", G_CALLBACK (pgui_action_shape_file_set), NULL);
+
+
+	/*
+	** PostGIS info in a table
+	*/
+	frame_pg = gtk_frame_new("PostGIS Connection");
+	table_pg = gtk_table_new(5, 3, TRUE);
+	gtk_container_set_border_width (GTK_CONTAINER (table_pg), 8);
+	gtk_table_set_col_spacings(GTK_TABLE(table_pg), 7);
+	gtk_table_set_row_spacings(GTK_TABLE(table_pg), 3);
+	/* User name row */
+	label = gtk_label_new("Username:");
+	entry_pg_user = gtk_entry_new();
+	gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 0, 1 );
+	gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_user, 1, 3, 0, 1 );
+	/* Password row */
+	label = gtk_label_new("Password:");
+	entry_pg_pass = gtk_entry_new();
+	gtk_entry_set_visibility( GTK_ENTRY(entry_pg_pass), FALSE);
+	gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 1, 2 );
+	gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_pass, 1, 3, 1, 2 );
+	/* Host and port row */
+	label = gtk_label_new("Server Host:");
+	entry_pg_host = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(entry_pg_host), "localhost");
+	gtk_entry_set_width_chars(GTK_ENTRY(entry_pg_host), text_width);
+	gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 2, 3 );
+	gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_host, 1, 2, 2, 3 );
+	entry_pg_port = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(entry_pg_port), "5432");
+	gtk_entry_set_width_chars(GTK_ENTRY(entry_pg_port), 8);
+	gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_port, 2, 3, 2, 3 );
+	/* Database row */
+	label = gtk_label_new("Database:");
+	entry_pg_db   = gtk_entry_new();
+	gtk_table_attach_defaults(GTK_TABLE(table_pg), label, 0, 1, 3, 4 );
+	gtk_table_attach_defaults(GTK_TABLE(table_pg), entry_pg_db, 1, 3, 3, 4 );
+	/* Test button row */
+	button_pg_test = gtk_button_new_with_label("Test Connection...");
+	gtk_table_attach_defaults(GTK_TABLE(table_pg), button_pg_test, 1, 2, 4, 5 );
+	g_signal_connect (G_OBJECT (button_pg_test), "clicked", G_CALLBACK (pgui_action_connection_test), NULL);
+	label_pg_connection_test = gtk_label_new("");
+	gtk_table_attach_defaults(GTK_TABLE(table_pg), label_pg_connection_test, 2, 3, 4, 5 );
+	/* Add table into containing frame */
+	gtk_container_add (GTK_CONTAINER (frame_pg), table_pg);
+
+	/*
+	** Configuration in a table
+	*/
+	frame_config = gtk_frame_new("Configuration");
+	table_config = gtk_table_new(2, 4, TRUE);
+	gtk_table_set_col_spacings(GTK_TABLE(table_config), 7);
+	gtk_table_set_row_spacings(GTK_TABLE(table_config), 3);
+	gtk_container_set_border_width (GTK_CONTAINER (table_config), 8);
+	/* Destination schemea row */
+	label = gtk_label_new("Destination Schema:");
+	entry_config_schema = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(entry_config_schema), "public");
+	gtk_entry_set_width_chars(GTK_ENTRY(entry_config_schema), text_width);
+	gtk_table_attach_defaults(GTK_TABLE(table_config), label, 0, 1, 0, 1 );
+	gtk_table_attach_defaults(GTK_TABLE(table_config), entry_config_schema, 1, 2, 0, 1 );
+	/* Destination table row */
+	label = gtk_label_new("Destination Table:");
+	entry_config_table = gtk_entry_new();
+	gtk_entry_set_width_chars(GTK_ENTRY(entry_config_table), text_width);
+	gtk_table_attach_defaults(GTK_TABLE(table_config), label, 0, 1, 1, 2 );
+	gtk_table_attach_defaults(GTK_TABLE(table_config), entry_config_table, 1, 2, 1, 2 );
+	/* SRID row */
+	label = gtk_label_new("SRID:");
+	entry_config_srid = gtk_entry_new();
+	gtk_entry_set_width_chars(GTK_ENTRY(entry_config_srid), text_width);
+	gtk_entry_set_text(GTK_ENTRY(entry_config_srid), "-1");
+	gtk_table_attach_defaults(GTK_TABLE(table_config), label, 2, 3, 0, 1 );
+	gtk_table_attach_defaults(GTK_TABLE(table_config), entry_config_srid, 3, 4, 0, 1 );
+	/* Geom column row */
+	label = gtk_label_new("Geometry Column:");
+	entry_config_geocolumn = gtk_entry_new();
+	gtk_entry_set_width_chars(GTK_ENTRY(entry_config_geocolumn), text_width);
+	gtk_entry_set_text(GTK_ENTRY(entry_config_geocolumn), "the_geom");
+	gtk_table_attach_defaults(GTK_TABLE(table_config), label, 2, 3, 1, 2 );
+	gtk_table_attach_defaults(GTK_TABLE(table_config), entry_config_geocolumn, 3, 4, 1, 2 );
+
+	/* Add table into containing frame */
+	gtk_container_add (GTK_CONTAINER (frame_config), table_config);
+
+
+	/*
+	** Row of action buttons
+	*/
+	hbox_buttons = gtk_hbox_new(TRUE, 15);
+	gtk_container_set_border_width (GTK_CONTAINER (hbox_buttons), 0);
+	/* Create the buttons themselves */
+	button_options = gtk_button_new_with_label("Options...");
+	button_import = gtk_button_new_with_label("Import");
+	button_cancel = gtk_button_new_with_label("Cancel");
+	/* Add actions to the buttons */
+	g_signal_connect (G_OBJECT (button_import), "clicked", G_CALLBACK (pgui_action_import), NULL);
+	g_signal_connect (G_OBJECT (button_options), "clicked", G_CALLBACK (pgui_action_options), NULL);
+	g_signal_connect (G_OBJECT (button_cancel), "clicked", G_CALLBACK (pgui_action_cancel), NULL);
+	/* And insert the buttons into the hbox */
+	gtk_box_pack_start(GTK_BOX(hbox_buttons), button_options, TRUE, TRUE, 0);
+	gtk_box_pack_end(GTK_BOX(hbox_buttons), button_cancel, TRUE, TRUE, 0);
+	gtk_box_pack_end(GTK_BOX(hbox_buttons), button_import, TRUE, TRUE, 0);
+
+	/*
+	** Log window
+	*/
+	frame_log = gtk_frame_new("Import Log");
+	gtk_container_set_border_width (GTK_CONTAINER (frame_log), 0);
+	textview_log = gtk_text_view_new();
+	textbuffer_log = gtk_text_buffer_new(NULL);
+	scrolledwindow_log = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolledwindow_log), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
+	gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview_log), textbuffer_log);
+	gtk_container_set_border_width (GTK_CONTAINER (textview_log), 5);
+	gtk_text_view_set_editable(GTK_TEXT_VIEW(textview_log), FALSE);
+	gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textview_log), FALSE);
+	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview_log), GTK_WRAP_WORD);
+	gtk_container_add (GTK_CONTAINER (scrolledwindow_log), textview_log);
+	gtk_container_add (GTK_CONTAINER (frame_log), scrolledwindow_log);
+
+	/*
+	** Main window 
+	*/
+	vbox_main = gtk_vbox_new(FALSE, 10);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox_main), 0);
+	/* Add the frames into the main vbox */
+	gtk_box_pack_start(GTK_BOX(vbox_main), frame_shape, FALSE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox_main), frame_pg, FALSE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox_main), frame_config, FALSE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox_main), hbox_buttons, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox_main), frame_log, TRUE, TRUE, 0);
+	/* and insert the vbox into the main window  */
+	gtk_container_add (GTK_CONTAINER (window_main), vbox_main);
+	/* make sure that everything, window and label, are visible */
+	gtk_widget_show_all (window_main);
+
+	return;
+}
+
+int
+main(int argc, char *argv[])
+{
+
+	/* initialize the GTK stack */
+	gtk_init(&argc, &argv);
+
+	/* set up the user interface */
+	pgui_create_main_window();
+	pgui_create_options_dialogue();
+	
+	/* set up and global variables we want before running */
+	gui_mode = 1;
+
+	/* start the main loop */
+	gtk_main();
+
+	return 0;
+}
+
+/**********************************************************************
+ * $Log$
+ *
+ **********************************************************************/

Added: trunk/loader/stringbuffer.c
===================================================================
--- trunk/loader/stringbuffer.c	2009-01-16 17:58:39 UTC (rev 3537)
+++ trunk/loader/stringbuffer.c	2009-01-19 21:33:14 UTC (rev 3538)
@@ -0,0 +1,568 @@
+/* 
+ *
+ * Copyright 2002 Thamer Alharbash
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Sringbuffer object:
+ *
+ * (*) allows printfing into a string,
+ * (*) fast string manipulation by keeping track of string length.
+ * (*) alignment of string against columns.
+ *
+ * Internally stringbuffer does not count the terminating null as the length.
+ * Therefore the raw string routines will always assume +1 when given length.
+ */
+
+#include "stringbuffer.h"
+
+/* * * * * * * * * * * * *
+ * raw string routines.  *
+ * * * * * * * * * * * * */
+
+/* just malloc out a string. */
+static char *allocate_string(int len)
+{
+	char *s;
+	s = malloc(sizeof(char) * len + 1); /* add for null termination. */
+	s[len] = 0;
+	return s;
+}
+
+/* extend a string. */
+static char *extend_string(char *str, int cur_len, int ex_len)
+{
+
+	str = realloc(str, (cur_len * sizeof(char)) + (ex_len * sizeof(char)) + (1 * sizeof(char)));
+	str[cur_len] = 0; /* make sure it's null terminated. */
+
+	return str;
+}
+
+/* get a substring. */
+static char *substring(char *begin, int len)
+{
+	char *new_string;
+
+	new_string = allocate_string(len);
+	memcpy(new_string, begin, len);
+	new_string[len] = 0;
+
+	return new_string;
+}
+
+/* FIXME: get rid of pesky strlen() */
+/* used in aligning -- we try to get words up to end. */
+static char *get_string_align(char *s, int end, int *len)
+{
+	char *cur_ptr;
+
+	if (s == 0 || *s == 0) /* end of string or no string. */
+		return NULL;
+
+	/* if strlen is smaller than len go ahead and just return it. */
+	if (strlen(s) < end)
+	{
+		*len = strlen(s);
+		return strdup(s);
+	}
+
+	/* otherwise we need to hop to len */
+	cur_ptr = &s[end - 1];
+
+	/* now check to see if we have a whitespace behind cur_ptr
+	 * if we do return at that point. */
+
+	for (; cur_ptr != s; cur_ptr--)
+	{
+		if (*cur_ptr == ' ' || *cur_ptr == '\t')
+		{
+			/* copy here and return. */
+			*len = (cur_ptr - s) + 1;
+			return (substring(s, *len));
+		}
+	}
+
+	/* keep walking till we find whitspace or end. */
+	for (cur_ptr = &s[end - 1]; *cur_ptr != 0 && *cur_ptr != ' ' && *cur_ptr != '\t'; cur_ptr++);
+
+	*len = (cur_ptr - s) + 1;
+	return (substring(s, *len));
+}
+
+/* zap newlines by placing spaces in their place.
+ * we use this before aligning. */
+static void stringbuffer_zap_newline(stringbuffer_t *sb)
+{
+
+	stringbuffer_replace_c(sb, '\n', ' ');
+	stringbuffer_replace_c(sb, '\r', ' ');
+}
+
+/* * * * * * * * * * * * * * *
+ * stringbuffer routines.    *
+ * * * * * * * * * * * * * * */
+
+/* create a new stringbuffer */
+stringbuffer_t *stringbuffer_create(void)
+{
+	stringbuffer_t *sb;
+
+	sb = malloc(sizeof(stringbuffer_t));
+	sb->len = 0;
+	sb->capacity = 0;
+	sb->buf = allocate_string(0);
+
+	return sb;
+}
+
+/* destroy the stringbuffer */
+void stringbuffer_destroy(stringbuffer_t *sb)
+{
+	free(sb->buf);
+	free(sb);
+}
+
+/* clear a string. */
+void stringbuffer_clear(stringbuffer_t *sb)
+{
+	sb->len = 0;
+	sb->buf[0] = 0;
+}
+
+/* append character to stringbuffer */
+void stringbuffer_append_c(stringbuffer_t *sb, char c)
+{
+	if (sb->capacity <= (sb->len))
+	{
+		sb->buf = extend_string(sb->buf, sb->len, STRINGBUFFER_CHUNKSIZE);
+		sb->capacity += STRINGBUFFER_CHUNKSIZE;
+	}
+
+	sb->buf[sb->len] = c;
+	sb->len++;
+	sb->buf[sb->len] = 0;
+}
+
+/* append string to stringbuffer */
+void stringbuffer_append(stringbuffer_t *sb, const char *s)
+{
+	int len = strlen(s);
+
+	/* increase capacity if needed. */
+	if (sb->capacity <= (len + sb->len))
+	{
+
+		/* if we're bigger than the chunksize then allocate len. */
+		if (len > STRINGBUFFER_CHUNKSIZE)
+		{
+
+			sb->buf = extend_string(sb->buf, sb->capacity, len);
+			sb->capacity += len;
+
+		}
+		else
+		{
+
+			/* otherwise allocate chunksize. */
+			sb->buf = extend_string(sb->buf, sb->capacity, STRINGBUFFER_CHUNKSIZE);
+			sb->capacity += STRINGBUFFER_CHUNKSIZE;
+		}
+	}
+
+	/* copy new string into place: keep in mind we know all
+	 * lengths so strcat() would be less effecient. */
+
+	memcpy(&sb->buf[sb->len], s, len);
+
+	sb->len += len;
+	sb->buf[sb->len] = 0;
+
+	return;
+}
+
+/* remove whitespace (including tabs) */
+stringbuffer_t *stringbuffer_trim_whitespace(stringbuffer_t *sb)
+{
+	char *newbuf;
+	int new_len;
+	int i, j;
+
+	if (sb->len == 0) /* empty string. */
+		return sb;
+
+	/* find beginning of string after tabs and whitespaces. */
+	for (i = 0; i < sb->len && (sb->buf[i] == ' ' || sb->buf[i] == '\t'); i++);
+
+	if (sb->buf[i] != '\0')
+	{
+
+		/* we do have whitespace in the beginning so find the end. */
+		for (j = (sb->len -1);(sb->buf[j] == ' ' || sb->buf[j] == '\t'); j--);
+
+		/* increment j since it's on the non whitespace character. */
+		j++;
+
+		/* create a new string. */
+		new_len = j - i;
+		newbuf = allocate_string(new_len);
+
+		/* copy in. */
+		memcpy(newbuf, &sb->buf[i], (j - i) * sizeof(char));
+		newbuf[new_len] = 0;
+
+		/* free up old. */
+		free(sb->buf);
+
+		/* set new. */
+		sb->buf = newbuf;
+		sb->len = new_len;
+		sb->capacity = new_len;
+
+
+	}
+	else
+	{
+
+		/* zap beginning of string. since its all whitespace. */
+		sb->buf[0] = 0;
+		sb->len = 0;
+	}
+
+	return sb;
+}
+
+/* get the last occurance of a specific character. useful for slicing. */
+char *stringbuffer_get_last_occurance(stringbuffer_t *sb, char c)
+{
+	char *ptr, *ptrend = NULL;
+	int i;
+
+	ptr = sb->buf;
+	for (i = 0;i < sb->len;i++)
+	{
+
+		if (ptr[i] == c)
+			ptrend = &ptr[i];
+	}
+
+	return ptrend;
+}
+
+/* remove the last newline character. */
+void stringbuffer_trim_newline(stringbuffer_t *sb)
+{
+	char *ptr;
+
+	ptr = stringbuffer_get_last_occurance(sb, '\n');
+	if (ptr != NULL)
+		*ptr = 0;
+
+
+	ptr = stringbuffer_get_last_occurance(sb, '\r');
+	if (ptr != NULL)
+		*ptr = 0;
+
+
+	sb->len = strlen(sb->buf);
+
+	return;
+}
+
+/* return the C string from the buffer. */
+const char *stringbuffer_getstring(stringbuffer_t *sb)
+{
+	return sb->buf;
+}
+
+/* set a string into a stringbuffer */
+void stringbuffer_set(stringbuffer_t *dest, const char *s)
+{
+	stringbuffer_clear(dest); /* zap */
+	stringbuffer_append(dest, s);
+}
+
+/* copy a stringbuffer into another stringbuffer */
+void stringbuffer_copy(stringbuffer_t *dest, stringbuffer_t *src)
+{
+	stringbuffer_set(dest, stringbuffer_getstring(src));
+}
+
+/* replace in stringbuffer occurances of c with replace */
+void stringbuffer_replace_c(stringbuffer_t *sb, char c, char replace)
+{
+	int i;
+
+	for (i = 0;i < sb->len;i++)
+	{
+		if (sb->buf[i] == c)
+			sb->buf[i] = replace;
+	}
+
+	return;
+}
+
+/* replace in stringbuffer occurances of c with replace */
+void stringbuffer_replace(stringbuffer_t *sb, const char *string, const char *replace)
+{
+	char *ptr;
+	int i;
+	int str_len = strlen(string);
+	stringbuffer_t *sb_replace;
+
+	if (string[0] == 0)
+		return; /* nothing to replace. */
+
+	sb_replace = stringbuffer_create();
+	ptr = sb->buf;
+
+	for (i = 0; i < sb->len; i++)
+	{
+
+		if ((sb->len - i) < str_len)
+		{
+
+			/* copy in. */
+			stringbuffer_copy(sb, sb_replace);
+
+			/* append what's left. */
+			stringbuffer_append(sb, &ptr[i]);
+
+			/* free up. */
+			stringbuffer_destroy(sb_replace);
+
+			/* we're done. */
+			return;
+		}
+
+		if (ptr[i] == string[0])
+		{
+
+			/* we know that we have at least enough to complete string. */
+			if (!memcmp(&ptr[i], string, str_len))
+			{
+
+				/* we have a match, replace. */
+				stringbuffer_append(sb_replace, replace);
+				i += (str_len - 1);
+				continue;
+			}
+		}
+
+		stringbuffer_append_c(sb_replace, ptr[i]);
+	}
+
+	/* we're done: we should only get here if the last string to
+	   be replaced ended the string itself. */
+
+	/* copy in. */
+	stringbuffer_copy(sb, sb_replace);
+
+	/* free up. */
+	stringbuffer_destroy(sb_replace);
+
+	/* we're done. */
+	return;
+
+}
+
+/* align a stringbuffer on begin and end columns. */
+void stringbuffer_align(stringbuffer_t *sb, int begin, int end)
+{
+	char *ptr, *word_string;
+	stringbuffer_t *aligned_string;
+	int len, i;
+
+	stringbuffer_zap_newline(sb);
+
+	aligned_string = stringbuffer_create();
+	ptr = sb->buf;
+
+	while (1)
+	{
+
+		word_string = get_string_align(ptr, end, &len);
+
+		if (word_string == NULL)
+			break;
+
+		ptr += len;
+
+		for (i = 0; i < begin; i++)
+			stringbuffer_append(aligned_string, " ");
+
+		stringbuffer_append(aligned_string, word_string);
+		stringbuffer_append(aligned_string, "\n");
+		free(word_string);
+
+	}
+
+	stringbuffer_copy(sb, aligned_string);
+	stringbuffer_destroy(aligned_string);
+
+	return;
+}
+
+/* stringbuffer_*printf* these all use snprintf/snvprintf internally */
+
+/* append vprintf with alignment. */
+void stringbuffer_avprintf_align(stringbuffer_t *sb, int start, int end, const char *fmt, va_list ap)
+{
+	stringbuffer_t *tmp_sb;
+	char *str;
+	int total, len;
+
+	/* our first malloc is bogus. */
+	len = 1;
+	str = malloc(sizeof(char) * len);
+	total = vsnprintf(str, len, fmt, ap);
+
+	/* total is the real length needed. */
+	free(str);
+	len = total + 1;
+	str = malloc(sizeof(char) * len);
+	vsnprintf(str, len, fmt, ap);
+
+	/* now align if we want to align. */
+	if (start != 0 && end != 0)
+	{
+
+		tmp_sb = stringbuffer_create();
+
+		stringbuffer_append(tmp_sb, str);
+		stringbuffer_align(tmp_sb, start, end);
+		stringbuffer_append(sb, stringbuffer_getstring(tmp_sb));
+
+		stringbuffer_destroy(tmp_sb);
+
+	}
+	else
+	{
+		stringbuffer_append(sb, str);
+	}
+
+	free(str);
+
+	return;
+}
+
+/* append printf. */
+void stringbuffer_aprintf(stringbuffer_t *sb, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+
+	stringbuffer_avprintf(sb, fmt, ap);
+
+	va_end(ap);
+}
+
+/* append printf with alignment. */
+void stringbuffer_aprintf_align(stringbuffer_t *sb, int start, int end, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+
+	stringbuffer_avprintf_align(sb, start, end, fmt, ap);
+
+	va_end(ap);
+}
+
+/* append vprintf. */
+void stringbuffer_avprintf(stringbuffer_t *sb, const char *fmt, va_list ap)
+{
+	stringbuffer_avprintf_align(sb, 0, 0, fmt, ap);
+}
+
+/* newline marking and sweeping. this wrecks the string inside
+ * the stringbuffer. */
+
+/* mark newlines to walk through.
+ * our sentinel is the null terminator.
+ * two null terminations marks the end of the string.
+ * we're guaranteed it is a unique sentinel since
+ * we never accept null terminators from outside sources
+ * and never build our own strings (obviously!) with
+ * null terminators inside of them.
+ */
+int stringbuffer_marknewlines(stringbuffer_t *sb)
+{
+	char *c;
+	int newline_count = 0;
+
+	/* first append one null termination to the end
+	 * to act as a proper terminator. */
+	stringbuffer_append_c(sb, 0);
+
+
+	c = sb->buf;
+	while (1)
+	{
+
+		if (*c == '\n')
+		{
+			newline_count++;
+			*c = 0;
+		}
+
+		c++;
+		if (*c == 0)
+			break;
+	}
+
+	return newline_count; /* return our line count. */
+}
+
+/* called _after_ newlines are marked. */
+const char *stringbuffer_getnextline(stringbuffer_t *sb, const char *cptr)
+{
+	const char *ptr;
+
+	if (cptr == NULL)
+	{
+
+		/* get first line. */
+		cptr = sb->buf;
+
+	}
+	else
+	{
+
+		for (ptr = cptr; *ptr != 0; ptr++);
+		if (*ptr == 0 && *(ptr + 1) == 0)
+		{
+			return NULL;
+
+		}
+		else
+		{
+			cptr = ptr + 1;
+
+		}
+	}
+
+	return cptr;
+}
+
+int stringbuffer_getlen(stringbuffer_t *sb)
+{
+	return sb->len;
+}

Added: trunk/loader/stringbuffer.h
===================================================================
--- trunk/loader/stringbuffer.h	2009-01-16 17:58:39 UTC (rev 3537)
+++ trunk/loader/stringbuffer.h	2009-01-19 21:33:14 UTC (rev 3538)
@@ -0,0 +1,66 @@
+/* 
+ *
+ * Copyright 2002 Thamer Alharbash
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Sringbuffer object:
+ *
+ * (*) allows printfing into a string,
+ * (*) fast string manipulation by keeping track of string length.
+ * (*) alignment of string against columns.
+ *
+ * Internally stringbuffer does not count the terminating null as the length.
+ * Therefore the raw string routines will always assume +1 when given length.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#define STRINGBUFFER_CHUNKSIZE 16
+
+typedef struct {
+    size_t len;
+    size_t capacity;
+    char *buf;
+} stringbuffer_t;
+
+extern stringbuffer_t *stringbuffer_create(void);
+extern void stringbuffer_destroy(stringbuffer_t *sb);
+extern void stringbuffer_clear(stringbuffer_t *sb);
+extern void stringbuffer_append_c(stringbuffer_t *sb, char c);
+extern void stringbuffer_append(stringbuffer_t *sb, const char *s);
+extern stringbuffer_t *stringbuffer_trim_whitespace(stringbuffer_t *sb);
+extern char *stringbuffer_get_last_occurance(stringbuffer_t *sb, char c);
+extern void stringbuffer_trim_newline(stringbuffer_t *sb);
+extern const char *stringbuffer_getstring(stringbuffer_t *sb);
+extern void stringbuffer_set(stringbuffer_t *dest, const char *s);
+extern void stringbuffer_copy(stringbuffer_t *dest, stringbuffer_t *src);
+extern void stringbuffer_replace_c(stringbuffer_t *sb, char c, char replace);
+extern void stringbuffer_replace(stringbuffer_t *sb, const char *string, const char *replace);
+extern void stringbuffer_align(stringbuffer_t *sb, int begin, int end);
+extern void stringbuffer_avprintf_align(stringbuffer_t *sb, int start, int end, const char *fmt, va_list ap);
+extern void stringbuffer_aprintf(stringbuffer_t *sb, const char *fmt, ...);
+extern void stringbuffer_aprintf_align(stringbuffer_t *sb, int start, int end, const char *fmt, ...);
+extern void stringbuffer_avprintf(stringbuffer_t *sb, const char *fmt, va_list ap);
+extern int stringbuffer_marknewlines(stringbuffer_t *sb);
+extern const char *stringbuffer_getnextline(stringbuffer_t *sb, const char *cptr);
+extern int stringbuffer_getlen(stringbuffer_t *sb);



More information about the postgis-commits mailing list