[
  {
    "path": ".gitignore",
    "content": "*.o\n*.so\n*.gem\npkg/\nbin/shp2sqlite\nsrc/shp2sqlite/shp2sqlite\nsrc/liblwgeom/liblwgeom.a\ndoc/*.html\n*.log\n"
  },
  {
    "path": "History.txt",
    "content": "=== 1.0.0 / 2009-06-02\n\n* 1 major enhancement\n\n  * Birthday!\n\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "\t\t   GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\n  This version of the GNU Lesser General Public License incorporates\nthe terms and conditions of version 3 of the GNU General Public\nLicense, supplemented by the additional permissions listed below.\n\n  0. Additional Definitions.\n\n  As used herein, \"this License\" refers to version 3 of the GNU Lesser\nGeneral Public License, and the \"GNU GPL\" refers to version 3 of the GNU\nGeneral Public License.\n\n  \"The Library\" refers to a covered work governed by this License,\nother than an Application or a Combined Work as defined below.\n\n  An \"Application\" is any work that makes use of an interface provided\nby the Library, but which is not otherwise based on the Library.\nDefining a subclass of a class defined by the Library is deemed a mode\nof using an interface provided by the Library.\n\n  A \"Combined Work\" is a work produced by combining or linking an\nApplication with the Library.  The particular version of the Library\nwith which the Combined Work was made is also called the \"Linked\nVersion\".\n\n  The \"Minimal Corresponding Source\" for a Combined Work means the\nCorresponding Source for the Combined Work, excluding any source code\nfor portions of the Combined Work that, considered in isolation, are\nbased on the Application, and not on the Linked Version.\n\n  The \"Corresponding Application Code\" for a Combined Work means the\nobject code and/or source code for the Application, including any data\nand utility programs needed for reproducing the Combined Work from the\nApplication, but excluding the System Libraries of the Combined Work.\n\n  1. Exception to Section 3 of the GNU GPL.\n\n  You may convey a covered work under sections 3 and 4 of this License\nwithout being bound by section 3 of the GNU GPL.\n\n  2. Conveying Modified Versions.\n\n  If you modify a copy of the Library, and, in your modifications, a\nfacility refers to a function or data to be supplied by an Application\nthat uses the facility (other than as an argument passed when the\nfacility is invoked), then you may convey a copy of the modified\nversion:\n\n   a) under this License, provided that you make a good faith effort to\n   ensure that, in the event an Application does not supply the\n   function or data, the facility still operates, and performs\n   whatever part of its purpose remains meaningful, or\n\n   b) under the GNU GPL, with none of the additional permissions of\n   this License applicable to that copy.\n\n  3. Object Code Incorporating Material from Library Header Files.\n\n  The object code form of an Application may incorporate material from\na header file that is part of the Library.  You may convey such object\ncode under terms of your choice, provided that, if the incorporated\nmaterial is not limited to numerical parameters, data structure\nlayouts and accessors, or small macros, inline functions and templates\n(ten or fewer lines in length), you do both of the following:\n\n   a) Give prominent notice with each copy of the object code that the\n   Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the object code with a copy of the GNU GPL and this license\n   document.\n\n  4. Combined Works.\n\n  You may convey a Combined Work under terms of your choice that,\ntaken together, effectively do not restrict modification of the\nportions of the Library contained in the Combined Work and reverse\nengineering for debugging such modifications, if you also do each of\nthe following:\n\n   a) Give prominent notice with each copy of the Combined Work that\n   the Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the Combined Work with a copy of the GNU GPL and this license\n   document.\n\n   c) For a Combined Work that displays copyright notices during\n   execution, include the copyright notice for the Library among\n   these notices, as well as a reference directing the user to the\n   copies of the GNU GPL and this license document.\n\n   d) Do one of the following:\n\n       0) Convey the Minimal Corresponding Source under the terms of this\n       License, and the Corresponding Application Code in a form\n       suitable for, and under terms that permit, the user to\n       recombine or relink the Application with a modified version of\n       the Linked Version to produce a modified Combined Work, in the\n       manner specified by section 6 of the GNU GPL for conveying\n       Corresponding Source.\n\n       1) Use a suitable shared library mechanism for linking with the\n       Library.  A suitable mechanism is one that (a) uses at run time\n       a copy of the Library already present on the user's computer\n       system, and (b) will operate properly with a modified version\n       of the Library that is interface-compatible with the Linked\n       Version.\n\n   e) Provide Installation Information, but only if you would otherwise\n   be required to provide such information under section 6 of the\n   GNU GPL, and only to the extent that such information is\n   necessary to install and execute a modified version of the\n   Combined Work produced by recombining or relinking the\n   Application with a modified version of the Linked Version. (If\n   you use option 4d0, the Installation Information must accompany\n   the Minimal Corresponding Source and Corresponding Application\n   Code. If you use option 4d1, you must provide the Installation\n   Information in the manner specified by section 6 of the GNU GPL\n   for conveying Corresponding Source.)\n\n  5. Combined Libraries.\n\n  You may place library facilities that are a work based on the\nLibrary side by side in a single library together with other library\nfacilities that are not Applications and are not covered by this\nLicense, and convey such a combined library under terms of your\nchoice, if you do both of the following:\n\n   a) Accompany the combined library with a copy of the same work based\n   on the Library, uncombined with any other library facilities,\n   conveyed under the terms of this License.\n\n   b) Give prominent notice with the combined library that part of it\n   is a work based on the Library, and explaining where to find the\n   accompanying uncombined form of the same work.\n\n  6. Revised Versions of the GNU Lesser General Public License.\n\n  The Free Software Foundation may publish revised and/or new versions\nof the GNU Lesser General Public License from time to time. Such new\nversions will be similar in spirit to the present version, but may\ndiffer in detail to address new problems or concerns.\n\n  Each version is given a distinguishing version number. If the\nLibrary as you received it specifies that a certain numbered version\nof the GNU Lesser General Public License \"or any later version\"\napplies to it, you have the option of following the terms and\nconditions either of that published version or of any later version\npublished by the Free Software Foundation. If the Library as you\nreceived it does not specify a version number of the GNU Lesser\nGeneral Public License, you may choose any version of the GNU Lesser\nGeneral Public License ever published by the Free Software Foundation.\n\n  If the Library as you received it specifies that a proxy can decide\nwhether future versions of the GNU Lesser General Public License shall\napply, that proxy's public statement of acceptance of any version is\npermanent authorization for you to choose that version for the\nLibrary.\n"
  },
  {
    "path": "Makefile",
    "content": "all:\n\tmake -C src install\n\tgem build gemspec\n\ntest: all\n\truby -Ilib tests/run.rb\n\ninstall: all\n\t# gem install *.gem\n\nclean:\n\tmake -C src clean\n\trm -f lib/geocoder/us/sqlite3.so\n\trm -f *.gem\n"
  },
  {
    "path": "Manifest.txt",
    "content": "History.txt\nManifest.txt\nREADME.rdoc\nRakefile\nlib/geocoder/us/database.rb\nlib/geocoder/us/numbers.rb\nlib/geocoder/us/address.rb\nlib/geocoder/us/constants.rb\ntests/database.rb\ntests/numbers.rb\ntests/generate.rb\ntests/run.rb\ntests/address.rb\ntests/benchmark.rb\ntests/constants.rb\ntests/data/address-sample.csv\ntests/data/locations.csv\ntests/data/db-test.csv\n"
  },
  {
    "path": "README.rdoc",
    "content": "= Geocoder::US\n\nGeocoder::US 2.0 is a software package designed to geocode US street\naddresses.  Although it is primarily intended for use with the US Census\nBureau's free TIGER/Line dataset, it uses an abstract US address data model\nthat can be employed with other sources of US street address range data.\n\nGeocoder::US 2.0 implements a Ruby interface to parse US street addresses, and\nperform fuzzy lookup against an SQLite 3 database. Geocoder::US is designed to\nreturn the best matches found, with geographic coordinates interpolated from\nthe street range dataset. Geocoder::US will fill in missing information, and\nit knows about standard and common non-standard postal abbreviations, ordinal\nversus cardinal numbers, and more.\n\nGeocoder::US 2.0 is shipped with a free US ZIP code data set, compiled from\npublic domain sources.\n\n== Synopsis\n\n  >> require 'geocoder/us'\n  >> db = Geocoder::US::Database.new(\"/opt/tiger/geocoder.db\")\n  >> p db.geocode(\"1600 Pennsylvania Av, Washington DC\")\n\n  [{:pretyp=>\"\", :street=>\"Pennsylvania\", :sufdir=>\"NW\", :zip=>\"20502\",\n    :lon=>-77.037528, :number=>\"1600\", :fips_county=>\"11001\", :predir=>\"\",\n    :precision=>:range, :city=>\"Washington\", :lat=>38.898746, :suftyp=>\"Ave\",\n    :state=>\"DC\", :prequal=>\"\", :sufqual=>\"\", :score=>0.906, :prenum=>\"\"}]\n\n== Web service\n\nThere is a small example webservice included in the gem at lib/geocoder/rest.rb. It requires Sinatra to run as well as setting the GEOCODER_DB environment variable. To run it:\n\n  GEOCODER_DB=/path/to/geocoder/geocoder.db ruby /path/to/gem/geocoder/lib/geocoder/us/rest.rb\n\nYou can then query the GeoCommons geocoder by calling the web service like:\n\n  http://localhost:9393/geocode.html?q=303+11th St NE,Washington,DC\n\n== Optional Options\n\ndbtype Geocoder::US::Database.new(\"/opt/tiger/geocoder.db\", {:dbtype => 1})\n\nThe dbtype option is used when your datasbase encodes it's geometry blogs according to a special format. The\nfirst and default value, is in a series of little-endian 4-byte ints (\"V*\")\nThe second is for ('CVVD*') format. Use option value 2 for this second type\n\ndebug  Geocoder::US::Database.new(\"/opt/tiger/geocoder.db\", {:debug => false})\n\ncache Geocoder::US::Database.new(\"/opt/tiger/geocoder.db\", {:cache => 50000})\nThe cache_size argument is measured in kilobytes and is used to set the SQLite cache size;\n larger values will trade memory for speed in long-running processes.\n\n== Prerequisites\n\nTo build Geocoder::US, you will need gcc/g++, make, bash or equivalent, the\nstandard *NIX 'unzip' utility, and the SQLite 3 executable and development\nfiles installed on your system.\n\nTo use the Ruby interface, you will need the 'Text' gem installed from\nrubyforge. To run the tests, you will also need the 'fastercsv' gem.\n\nAdditionally, you will need a custom build of the 'sqlite3-ruby' gem that\nsupports loading extension modules in SQLite. You can get a patched version of\nthis gem from http://github.com/schuyler/sqlite3-ruby/. Until the sqlite3-ruby\nmaintainers roll in the relevant patch, you will need *this* version.\n\n*NOTE*: If you do not have /usr/include/sqlite3ext.h installed, then your\nsqlite3 binaries are probably not configured to support dynamic extension\nloading. If not, you *must* compile and install SQLite from source, or rebuild\nyour system packages. This is not believed to be a problem on Debian/Ubuntu,\nbut is known to be a problem with Red Hat/CentOS.\n\n*NOTE*: If you *do* have to install from source, make sure that the\nsource-installed 'sqlite3' program is in your path before proceeding (and not\nthe system-installed version), using `which sqlite3`. Also, be sure that you've\nadded your source install prefix (usually /usr/local) to /etc/ld.so.conf (or\nits moral equivalent) and that you've run /sbin/ldconfig.\n\n== Thread safety\n\nSQLite 3 is not designed for concurrent use of a single database handle across\nmultiple threads. Therefore, to prevent segfaults, Geocoder::US::Database\nimplements a global mutex that wraps all database access. The use of this mutex\nwill ensure stability in multi-threaded applications, but incurs a performance\npenalty. However, since the database is read-only from Ruby, there's no reason\nin principle why multi-threaded apps can't each have their own database handle.\n\nTo disable the mutex for better performance, you can do the following:\n\n * Read the following and make sure you understand them:\n    * http://www.sqlite.org/faq.html#q6\n    * http://www.sqlite.org/cvstrac/wiki?p=MultiThreading\n * Make sure you have compiled SQLite 3 with thread safety enabled.\n * Instantiate a separate Geocoder::US::Database object for *each* thread\n   in your Ruby script, and pass :threadsafe => true to new() to disable mutex\n   synchronization.\n\nPer the SQLite 3 documentation, do *not* attempt to retain a\nGeocoder::US::Database object across a fork! \"Problems will result if you do.\"\n\n== Building Geocoder::US\n\nUnpack the source and run 'make'. This will compile the SQLite 3 extension\nneeded by Geocoder::US, the Shapefile import utility, and the Geocoder-US\ngem.\n\nYou can run 'make install' as root to install the gem systemwide.\n\n== Generating a Geocoder::US Database\n\nBuild the package from source as described above. Generating the database\ninvolves three basic steps:\n\n* Import the Shapefile data into an SQLite database.\n* Build the database indexes.\n* Optionally, rebuild the database to cluster indexed rows.\n\nWe will presume that you are building a Geocoder::US database from TIGER/Line,\nand that you have obtained the complete set of TIGER/Line ZIP files, and put\nthe entire tree in /opt/tiger. Please adjust these instructions as needed.\n\nA full TIGER/Line database import takes ten hours to run on a normal Amazon\nEC2 instance, and takes up a little over 5 gigabytes after all is said and\ndone.  You will need to have at least 12 gigabytes of free disk space *after*\ndownloading the TIGER/Line dataset, if you are building the full database. \n\n=== Import TIGER/Line\n\nFrom inside the Geocoder::US source tree, run the following:\n\n  $ build/tiger_import /opt/tiger/geocoder.db /opt/tiger\n\nThis will unpack each TIGER/Line ZIP file to a temporary directory, and\nperform the extract/transform/load sequence to incrementally build the\ndatabase. The process takes about 10-12 hours on a normal Amazon EC2 instance,\nor about 5 CPU hours flat out on a modern PC. Note that not all TIGER/Line\nsource files contain address range information, so you will see error messages\nfor some counties, but this is normal.\n\nIf you only want to import specific counties, you can pipe a list of\nTIGER/Line county directories to tiger_import on stdin. For example,\nthe following will install just the data for the state of Delaware:\n\n  $ ls -d /opt/tiger/10_DELAWARE/1* | build/tiger_import ~/delaware.db\n\nThe tiger_import process uses a binary utility, shp2sqlite, which is derived\nfrom shp2pgsql, which ships with PostGIS. The shp2sqlite utility converts\n.shp and .dbf files into SQL suitable for import into SQLite. This SQL\nis then piped into the sqlite3 command line tool, where it is loaded into\ntemporary tables, and then a set of static SQL statements (kept in the sql/\ndirectory) are used to transform this data and import it into the database\nitself.\n\n== Build metaphones using Ruby metaphone\n\nrun bin/rebuild_metaphones /opt/tiger/geocoder.db \n\nThis creates the metaphones using Ruby's metaphone function and will produce better geocoding results.\n\n=== Build the indexes\n\nAfter the database import is complete, you will want to construct the database\nindexes:\n\n  $ build/build_indexes /opt/tiger/geocoder.db\n\nThis process takes 25 minutes on an EC2 instance (8 CPU minutes), but it's a\n*lot* faster than building the indexes incrementally during the import\nprocess. Basically, this process simply feeds SQL statements to the sqlite3\nutility to construct the indexes on the existing database.\n\n=== Cluster the database tables (optional)\n\nAs a final optional step, you can cluster the database tables according to\ntheir indexes, which will make the database smaller, and lookups faster. This\nprocess will take an hour or two, and may be a micro-optimization.\n\n  $ build/rebuild_cluster /opt/tiger/geocoder.db\n\nYou will need as much free disk space to run rebuild_cluster as the database\ntakes up, because the process essentially reconstructs the database in a new\nfile, and then it renames the new database over top of the old.\n\n== Running the unit tests\n\nFrom within the source tree, you can run the following:\n\n  $ ruby tests/run.rb\n\nThis tests the libraries, except for the database routines. If you have a\ndatabase built, you can run the test harness like so:\n\n  $ ruby tests/run.rb /opt/tiger/geocoder.db\n\nThe full test suite may take 30 or so seconds to run completely.\n\n== License\n\nGeocoder::US 2.0 was based on earlier work by Schuyler Erle on\na Perl module of the same name. You can find it at\nhttp://search.cpan.org/~sderle/.\n\nGeocoder::US 2.0 was written by Schuyler Erle, of Entropy Free LLC,\nwith the gracious support of FortiusOne, Inc. Please send bug reports,\npatches, kudos, etc. to patches at geocoder.us.\n\nCopyright (c) 2009 FortiusOne, Inc.\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n"
  },
  {
    "path": "REST.rdoc",
    "content": "GET /1.0/geocode/address.json\n\nThe geocode/address endpoint returns the interpolated latitude and longitude of\na US street address or street intersection. When given a US city or ZIP code,\nthe approximate center point of that place will be returned instead.\n\nThe geocoder attempts to return the most accurate possible result, including,\nwhere possible, correcting the given street type, city, or postal code, and\nidentifying and correcting misspellings in the street or city name in the given\naddress.\n\nCurrently, address geocoding only works in the United States.\n\nParameters:\n\n  q = a string containing a US street address.\n\nReturns a GeoJSON feature collection:\n\n    {\n        \"type\": \"FeatureCollection\",\n        \"features\": [\n            {\n                \"type\": \"Feature\",\n                \"properties\": {\n                    \"number\": \"41\",\n                    \"street\": \"Decatur St\",\n                    \"city\": \"San Francisco\",\n                    \"state\": \"CA\",\n                    \"zip\": \"94103\",\n                    \"fips_county\": \"06075\",\n                    \"score\": 1.0,\n                    \"precision\":\"range\"\n                },\n                \"geometry\": {\n                    \"type\": \"Point\",\n                    \"coordinates\": [-122.406032, 37.772502]\n                }\n            }\n        ],\n        \"address\":\"41 Decatur St, San Francisco CA 94103\"\n    }\n\n\nEach address match in the feature collection contains some combination of the\nfollowing properties:\n\n    number\n        The building number of the address. When a building number is not\n        included in a range stored in the address database, the nearest\n        known building number will be returned in its place.\n\n    street\n        The name of the street found in the database that matches the address,\n        given in a normalized form. \n\n    street1 / street2\n        When an address is parsed as an intersection, the intersecting streets\n        are returned as `street1` and `street2` in place of the `number` and\n        `street` fields.\n\n    city\n        The city matching the given address. In the US, this is typically\n        determined from the matching ZIP code, so, for ZIP codes that cover\n        more than one named place, the results may be different from what you\n        expect, but will still be suitable for postal addressing.\n\n    state\n        The two letter postal abbreviation of the state containing the matching\n        address.\n\n    zip\n        In the US, the five digit ZIP code of the matching address.\n\n    plus4\n        In the US, the ZIP+4 extension parsed from the address, if any. This\n        extension is not actually used in the geocoding process, but is\n        returned for convenience.\n\n    fips_county\n        In the US, the FIPS 6-4 code of the county containing the address.\n\n    prenum / sufnum \n        If the building number has a non-numeric prefix, it will be returned in\n        `prenum`. Ditto `sufnum` for non-numeric suffixes.\n\n    precision\n        The qualitative precision of the geocode. The value will be one of\n        `intersection`, 'range`, `street`, `zip`, or `city`.\n\n    score\n        The percentage of text match between the given address and the geocoded\n        result, expressed as a float between 0 and 1. A higher score indicates\n        a closer match. Results with a score below 0.5 should be regarded with\n        care.\n"
  },
  {
    "path": "TODO.txt",
    "content": "1. Check interpolate measure: scale longitude or not?\n5. Intersections...\n    - import ALL linestrings (even those with without ranges)\n    - throw away internal points on lines that don't have ranges\n7. Documentation (*)\n8. Make SQLite memory cache size an option to the Database constructor\n9. Precision and accuracy measure\n10. Street line set back\n"
  },
  {
    "path": "bin/rebuild_metaphones",
    "content": "#!/usr/bin/ruby\n\nrequire 'rubygems'\nrequire 'sqlite3'\nrequire 'text'\n\nif(ARGV.length < 1)\nprint \"Missing SQLite file parameter\"\nprintf \"\\nUSAGE:\\n\"\nprint \"\"\"./rebuild_metaphones [SQLite File]\n  [SQLite File] - SQLite file generated by the geocoder.\n\"\"\"\nexit\nend\n\n    @db = SQLite3::Database.new(ARGV[0])\n    @db.create_function(\"metaphone\", 2) do |func, string, len|\n      test = string.to_s.gsub(/\\W/o, \"\")\n      if test =~ /^(\\d+)/o\n        mph = $1\n      elsif test =~ /^([wy])$/io\n        mph = $1\n      else\n        mph = Text::Metaphone.metaphone test\n      end\n      func.result = mph[0...len.to_i]\n    end\n    sql = \"update place set city_phone = metaphone(city,5)\"\n    \n    @db.execute sql\n    \n    @db.close\n"
  },
  {
    "path": "build/build_indexes",
    "content": "#!/bin/bash\n\nBASE=$(dirname $0)\nPATH=$PATH:$BASE/bin\nSQL=\"$BASE/sql\"\n\n# Just run the SQL that constructs the indexes.\nsqlite3 $1 < ${SQL}/index.sql\n"
  },
  {
    "path": "build/rebuild_cluster",
    "content": "#!/bin/bash\n\nBASE=$(dirname $0)\nPATH=$PATH:$BASE/bin\nSQL=\"$BASE/sql\"\n\nOLD_DB=$1\nDATABASE=${OLD_DB}.$$\n\n[ -r $DATABASE ] && echo \"$DATABASE already exists.\" && exit -1\n[ ! -r $OLD_DB ] && echo \"Can't read $OLD_DB.\" && exit -1\n\n# Create a shiny new database, attach the old one,\n#   extract the data from it, and then index that.\n#   Finally, overwrite the old database with the new one.\n( cat ${SQL}/create.sql && \\\n  echo \"ATTACH DATABASE '${OLD_DB}' AS old;\" && \\\n  cat ${SQL}/cluster.sql && \\\n  echo \"DETACH DATABASE old;\" && \\\n  cat ${SQL}/index.sql && \\\n  echo \"ANALYZE;\" ) | sqlite3 $DATABASE \\\n  && mv $DATABASE $OLD_DB\n"
  },
  {
    "path": "build/sql/cluster.sql",
    "content": ".echo on\n-- turn off various pragmas to make SQLite faster\nPRAGMA temp_store=MEMORY;\nPRAGMA journal_mode=OFF;\nPRAGMA synchronous=OFF;\nPRAGMA cache_size=500000;\nPRAGMA count_changes=0;\nBEGIN TRANSACTION;\n-- order the contents of each table by their indexes to reduce\n--   the number of disk pages that need to be read on each query.\nINSERT INTO place SELECT * FROM old.place ORDER BY zip, priority;\nINSERT INTO edge SELECT * FROM old.edge ORDER BY tlid;\nINSERT INTO feature SELECT * FROM old.feature ORDER BY street_phone, zip;\nINSERT INTO feature_edge SELECT * FROM old.feature_edge ORDER BY fid;\nINSERT INTO range SELECT * FROM old.range ORDER BY tlid;\nCOMMIT;\n"
  },
  {
    "path": "build/sql/convert.sql",
    "content": "BEGIN;\n-- start by indexing the temporary tables created from the input data.\nCREATE INDEX featnames_tlid ON tiger_featnames (tlid);\nCREATE INDEX addr_tlid ON tiger_addr (tlid);\nCREATE INDEX edges_tlid ON tiger_edges (tlid);\n\n-- generate a summary table matching each edge to one or more ZIPs\n--   for those edges that are streets and have a name\nCREATE TEMPORARY TABLE linezip AS\n    SELECT DISTINCT tlid, zip FROM (\n        SELECT tlid, zip FROM tiger_addr a\n        UNION\n        SELECT tlid, zipr AS zip FROM tiger_edges e\n           WHERE e.mtfcc LIKE 'S%' AND zipr <> \"\" AND zipr IS NOT NULL\n        UNION\n        SELECT tlid, zipl AS zip FROM tiger_edges e\n           WHERE e.mtfcc LIKE 'S%' AND zipl <> \"\" AND zipl IS NOT NULL\n    ) AS whatever;\n\nCREATE INDEX linezip_tlid ON linezip (tlid);\n\n-- generate features from the featnames table for each desired edge\n--   computing the metaphone hash of the name in the process.\n\n-- CREATE TEMPORARY TABLE sqlite_sequence (\n--  name VARCHAR(255),\n--  seq INTEGER);\n\nCREATE TEMPORARY TABLE feature_bin (\n  fid INTEGER PRIMARY KEY AUTOINCREMENT,\n  street VARCHAR(100),\n  street_phone VARCHAR(5),\n  paflag BOOLEAN,\n  zip CHAR(5));\n\nINSERT OR IGNORE INTO sqlite_sequence (name, seq) VALUES ('feature_bin',0);\nUPDATE sqlite_sequence\n    SET seq=(SELECT max(fid) FROM feature)\n    WHERE name=\"feature_bin\";\n\nINSERT INTO feature_bin\n    SELECT DISTINCT NULL, fullname, metaphone(name,5), paflag, zip\n        FROM linezip l, tiger_featnames f\n        WHERE l.tlid=f.tlid AND name <> \"\" AND name IS NOT NULL;\n\nCREATE INDEX feature_bin_idx ON feature_bin (street, zip);\n\nINSERT INTO feature_edge\n    SELECT DISTINCT fid, f.tlid\n        FROM linezip l, tiger_featnames f, feature_bin b\n        WHERE l.tlid=f.tlid AND l.zip=b.zip\n          AND f.fullname=b.street AND f.paflag=b.paflag;\n\n-- SELECT min(fid),max(fid) FROM feature_bin;\n\nINSERT INTO feature\n    SELECT * FROM feature_bin;\n\n-- generate edges from the edges table for each desired edge, running\n--   a simple compression on the WKB geometry (because they're all\n--   linestrings).\nINSERT OR IGNORE INTO edge\n    SELECT l.tlid, compress_wkb_line(the_geom) FROM\n        (SELECT DISTINCT tlid FROM linezip) AS l, tiger_edges e\n        WHERE l.tlid=e.tlid AND fullname <> \"\" AND fullname IS NOT NULL;\n\n-- generate all ranges from the addr table, stripping off any non-digit\n--   prefixes and putting them in a separate column.\nINSERT INTO range\n    SELECT tlid, digit_suffix(fromhn), digit_suffix(tohn),\n           nondigit_prefix(fromhn), zip, side\n    FROM tiger_addr;\nEND;\n\nDROP TABLE feature_bin;\nDROP TABLE linezip;\nDROP TABLE tiger_addr;\nDROP TABLE tiger_featnames;\nDROP TABLE tiger_edges;\n\n"
  },
  {
    "path": "build/sql/create.sql",
    "content": "-- initialize the database tables.\n-- 'place' contains the gazetteer of place names.\nCREATE TABLE place(\n  zip CHAR(5),\n  city VARCHAR(100),\n  state CHAR(2),\n  city_phone VARCHAR(5),\n  lat NUMERIC(9,6),\n  lon NUMERIC(9,6),\n  status CHAR(1),\n  fips_class CHAR(2),\n  fips_place CHAR(7),\n  fips_county CHAR(5),\n  priority char(1));\n-- 'edge' stores the line geometries and their IDs.\nCREATE TABLE edge (\n  tlid INTEGER(10) PRIMARY KEY,\n  geometry BLOB);\n-- 'feature' stores the name(s) and ZIP(s) of each edge.\nCREATE TABLE feature (\n  fid INTEGER PRIMARY KEY,\n  street VARCHAR(100),\n  street_phone VARCHAR(5),\n  paflag BOOLEAN,\n  zip CHAR(5));\n-- 'feature_edge' links each edge to a feature.\nCREATE TABLE feature_edge (\n  fid INTEGER,\n  tlid INTEGER);\n-- 'range' stores the address range(s) for each edge.\nCREATE TABLE range (\n  tlid INTEGER(10),\n  fromhn INTEGER(6),\n  tohn INTEGER(6),\n  prenum VARCHAR(12),\n  zip CHAR(5),\n  side CHAR(1));\n"
  },
  {
    "path": "build/sql/index.sql",
    "content": ".echo on\nPRAGMA temp_store=MEMORY;\nPRAGMA journal_mode=MEMORY;\nPRAGMA synchronous=OFF;\nPRAGMA cache_size=500000;\nPRAGMA count_changes=0;\n-- create indexes for all the relevant ways each table is queried.\nCREATE INDEX place_city_phone_state_idx ON place (city_phone, state);\nCREATE INDEX place_zip_priority_idx ON place (zip, priority);\nCREATE INDEX feature_street_phone_zip_idx ON feature (street_phone, zip);\nCREATE INDEX feature_edge_fid_idx ON feature_edge (fid);\nCREATE INDEX range_tlid_idx ON range (tlid);\n"
  },
  {
    "path": "build/sql/setup.sql",
    "content": "-- create temporary tables to hold the TIGER/Line data before it's\n--   transformed and loaded into the permanent tables.\n--\n-- this file was made by running 'shp2pgsql -p' on each of the \n--   TIGER/Line shapefiles and then massaging the result by hand.\n--\nPRAGMA temp_store=MEMORY;\nPRAGMA journal_mode=MEMORY;\nPRAGMA synchronous=OFF;\nPRAGMA cache_size=500000;\nPRAGMA count_changes=0;\nCREATE TEMPORARY TABLE \"tiger_edges\" (\n\"statefp\" varchar(2),\n\"countyfp\" varchar(3),\n\"tlid\" int8,\n\"tfidl\" int8,\n\"tfidr\" int8,\n\"mtfcc\" varchar(5),\n\"fullname\" varchar(100),\n\"smid\" varchar(22),\n\"lfromadd\" varchar(12),\n\"ltoadd\" varchar(12),\n\"rfromadd\" varchar(12),\n\"rtoadd\" varchar(12),\n\"zipl\" varchar(5),\n\"zipr\" varchar(5),\n\"featcat\" varchar(1),\n\"hydroflg\" varchar(1),\n\"railflg\" varchar(1),\n\"roadflg\" varchar(1),\n\"olfflg\" varchar(1),\n\"passflg\" varchar(1),\n\"divroad\" varchar(1),\n\"exttyp\" varchar(1),\n\"ttyp\" varchar(1),\n\"deckedroad\" varchar(1),\n\"artpath\" varchar(1),\n\"persist\" varchar(1),\n\"gcseflg\" varchar(1),\n\"offsetl\" varchar(1),\n\"offsetr\" varchar(1),\n\"tnidf\" int8,\n\"tnidt\" int8,\n\"the_geom\" blob\n);\n-- SELECT AddGeometryColumn('','edges','the_geom','-1','MULTILINESTRING',2);\nCREATE TEMPORARY TABLE \"tiger_featnames\" (\n\"tlid\" int8,\n\"fullname\" varchar(100),\n\"name\" varchar(100),\n\"predirabrv\" varchar(15),\n\"pretypabrv\" varchar(50),\n\"prequalabr\" varchar(15),\n\"sufdirabrv\" varchar(15),\n\"suftypabrv\" varchar(50),\n\"sufqualabr\" varchar(15),\n\"predir\" varchar(2),\n\"pretyp\" varchar(3),\n\"prequal\" varchar(2),\n\"sufdir\" varchar(2),\n\"suftyp\" varchar(3),\n\"sufqual\" varchar(2),\n\"linearid\" varchar(22),\n\"mtfcc\" varchar(5),\n\"paflag\" varchar(1));\nCREATE TEMPORARY TABLE \"tiger_addr\" (\n\"tlid\" int8,\n\"fromhn\" varchar(12),\n\"tohn\" varchar(12),\n\"side\" varchar(1),\n\"zip\" varchar(5),\n\"plus4\" varchar(4),\n\"fromtyp\" varchar(1),\n\"totyp\" varchar(1),\n\"fromarmid\" int4,\n\"toarmid\" int4,\n\"arid\" varchar(22),\n\"mtfcc\" varchar(5));\n"
  },
  {
    "path": "build/tiger2009_import",
    "content": "#!/bin/bash\n\nTMP=\"/tmp/tiger-import.$$\"\nSHPS=\"edges\"\nDBFS=\"featnames addr\"\nBASE=$(dirname $0)\nPATH=$PATH:$BASE\nSQL=\"$BASE/sql\"\nHELPER_LIB=\"$BASE/../lib/geocoder/us/sqlite3.so\"\nDATABASE=$1\nshift\n\nmkdir -p $TMP || exit 1\n\n# Initialize the database if it doesn't exist.\n[ ! -r $DATABASE ] && cat ${SQL}/{create,place}.sql | sqlite3 $DATABASE\n \n# Marshal the county directories to import.\n#\n# If no directory was given on the command-line, read a list from STDIN.\nif [ x\"$1\" = x\"\" ]; then\n    cat\nelse\n    # Otherwise, find all of the contents of each state directory.\n    ls -d $1/[0-9]* | while read state; do\n        ls -d ${state}/[0-9]*\n    done\nfi | while read county; do\n    echo \"--- $county\"\n    # Unpack the county files into the temp directory.\n    for file in $SHPS $DBFS; do\n\tZIP=$(ls ${county}/*_${file}.zip 2>/dev/null)\n\tSHP=$(ls ${county}/*_${file}.* 2>/dev/null)\n\tif [ x\"$ZIP\" != x\"\" ]; then\n\t    unzip -q $ZIP -d $TMP\n\telif [ x\"$SHP\" != x\"\" ]; then\n\t    ln -s $SHP $TMP\n\tfi\n    done\n    # Generate an SQL stream to feed into the sqlite3 binary.\n    # Start by loading the helper libs and initializing the temporary tables\n    #   that will hold the TIGER data before ETL.\n    (echo \".load $HELPER_LIB\" && \\\n     cat ${SQL}/setup.sql && \\\n     for file in $SHPS; do\n       # Convert each Shapefile into SQL statements.\n       shp2sqlite -aS ${TMP}/*_${file}.shp tiger_${file}\n     done && \\\n     for file in $DBFS; do\n       # Convert each DBF into SQL statements likewise.\n       shp2sqlite -an ${TMP}/*_${file}.dbf tiger_${file}\n     done && \\\n     cat ${SQL}/convert.sql) | sqlite3 $DATABASE\n    # Finally, do the transform/load phase (convert.sql)\n    # and clean up the temporary files.\n    rm -f $TMP/*\ndone 2>&1 | tee import-$$.log\nrm -rf $TMP\n\n"
  },
  {
    "path": "build/tiger_import",
    "content": "#!/bin/bash\n\nTMP=\"/tmp/tiger-import.$$\"\nSHPS=\"edges\"\nDBFS=\"featnames addr\"\nBASE=$(dirname $0)\nPATH=$PATH:$BASE\nSQL=\"$BASE/sql\"\nHELPER_LIB=\"$BASE/../lib/geocoder/us/sqlite3.so\"\nSHP2SQLITE=../src/shp2sqlite/shp2sqlite \nDATABASE=$1\nSOURCE=$2\nshift\nshift\n\nmkdir -p $TMP || exit 1\n\n# Initialize the database if it doesn't exist.\n# Added places back in after adding the \"drop if exists\" directive to the SQL file. theduckylittle, 2011/12/15\n[ ! -r $DATABASE ] && cat ${SQL}/{create,place}.sql | sqlite3 $DATABASE\n#[ ! -r $DATABASE ] && cat ${SQL}/create.sql | sqlite3 $DATABASE\n \n# Marshal the county directories to import.\n#\n# If no directory was given on the command-line, read a list of county IDs from STDIN.\nif [ x\"$1\" != x\"\" ]; then\n    cat\nelse\n    # Otherwise, find all of the IDs from the contents of the directory structure.\n    ls $SOURCE/tl_*_edges.zip | while read file; do\n        file=$(basename $file)\n        code=${file##tl_????_}\n        echo ${code%%_edges.zip}\n    done\nfi | sort | while read code; do\n    echo \"--- $code\"\n    # Unpack the county files into the temp directory.\n    for file in $SHPS $DBFS; do\n\tZIP=$(ls $SOURCE/*_${code}_${file}.zip 2>/dev/null)\n\tSHP=$(ls $SOURCE/*_${code}_${file}.* 2>/dev/null)\n\tif [ x\"$ZIP\" != x\"\" ]; then\n\t    unzip -q $ZIP -d $TMP\n\telif [ x\"$SHP\" != x\"\" ]; then\n\t    ln -s $SHP $TMP\n\tfi\n    done\n    # Generate an SQL stream to feed into the sqlite3 binary.\n    # Start by loading the helper libs and initializing the temporary tables\n    #   that will hold the TIGER data before ETL.\n    (echo \".load $HELPER_LIB\" && \\\n     cat ${SQL}/setup.sql && \\\n     for file in $SHPS; do\n       # Convert each Shapefile into SQL statements.\n\t${SHP2SQLITE} -aS ${TMP}/*_${file}.shp tiger_${file}\n     done && \\\n     for file in $DBFS; do\n       # Convert each DBF into SQL statements likewise.\n       shp2sqlite -an ${TMP}/*_${file}.dbf tiger_${file}\n     done && \\\n     cat ${SQL}/convert.sql) | sqlite3 $DATABASE\n    # Finally, do the transform/load phase (convert.sql)\n    # and clean up the temporary files.\n    rm -f $TMP/*\ndone 2>&1 | tee import-$$.log\nrm -rf $TMP\n\n"
  },
  {
    "path": "conf/geocoder-us/geocoder.ru",
    "content": "require 'sinatra'\ndisable :run, :reload\nrequire 'geocoder/us/rest'\nrun Sinatra::Application\n"
  },
  {
    "path": "conf/geocoder-us/unicorn.rb",
    "content": "worker_processes 4\nuser \"www-data\", \"www-data\"\nlisten \"/var/run/geocoder-us/unicorn.sock\", :backlog => 64\npid \"/var/run/geocoder-us/unicorn.pid\"\nstderr_path \"/var/log/geocoder-us/geocoder-err.log\"\nstdout_path \"/var/log/geocoder-us/geocoder-out.log\"\n\n# Have each process listen on a local port for debugging purposes.\nafter_fork do |server, worker|\n    addr = \"127.0.0.1:#{40000 + worker.nr}\"\n    server.listen(addr, :tries => 1, :delay => 5, :tcp_nopush => true)\nend\n"
  },
  {
    "path": "conf/init/geocoder-us.conf",
    "content": "description\t\"geocoder.us\"\n\nstart on runlevel [2345]\nstop on runlevel [!2345]\n\nrespawn\nexpect daemon\nscript\n    . /etc/default/geocoder-us\n    unicorn -c /etc/geocoder-us/unicorn.rb /etc/geocoder-us/geocoder.ru\nend script\n"
  },
  {
    "path": "debian/README.Debian",
    "content": "geocoder-us for Debian\n----------------------\n\nThe Geocoder::US package is a Ruby library that uses a database built from the\nUS Census Bureau's TIGER/Line data to interpolate a latitude/longitude\ncoordinate for a given US street address.\n\nBinary shared objects\n---------------------\n\nThe Geocoder::US module depends on being able to load a native extension module\nin its SQLite driver. For this reason, a version of libsqlite-ruby >= 1.3.0 is\nneeded. The module is built and included in the .deb as `sqlite.so`, and it is\ninstalled in the same directory as the Ruby modules. This may not be ideal, but\nthis makes it easy for the Geocoder::US library to find it there; otherwise, a\nconfiguration option would be necessary.\n\nREST API server\n---------------\n\nThe library's API centers on a single method 'geocode' to the\nGeocoder::US::Database class that takes an address string and returns a list of\ndicts containing the most likely matches with coordinates.\n\nThe `geocode` method is wrapped in a very simple Sinatra application with a single\nendpoint `/geocode` and a single argument `q`, which returns the result of the\ngeocode method in JSON format.\n\nThe Sinatra web framework does not support running as a daemon on its own, so\nthe Thin web server is used as a container for the application. This package\ncreates an `/etc/geocoder-us` directory containing two files:\n\n`/etc/geocoder-us/geocoder.ru` is the \"rackup\" adapter between Thin and Sinatra\nand should probably not be changed. This file doesn't have to live in /etc, but\nI couldn't figure out where else to put it.\n\n`/etc/geocoder-us/thin.yml` contains the configuration options to run the Thin\nserver. This file as packaged runs the REST server as the www-data user on port\n8080. This file *probably* doesn't need to be changed, but if the server starts\ndoing weird things, different options to control Thin's behavior can be set\nhere.\n\nThe package creates `/var/log/geocoder-us` and `/var/run/geocoder-us`\ndirectories for the Thin log file and PID file, respectively, and chowns them\nto www-data.\n\nAn init script is also included in `/etc/init.d/geocoder-us`. It is heavily\nhacked from the default Debian init.ex script to support the weirdnesses of\nThin, but it is LSB compliant and supports the `status` command.\n\nWhere to put the database\n-------------------------\n\nThe location of the database file should be set in `/etc/default/geocoder-us`.\nThe package creates a `/var/lib/geocoder-us` directory and configures the\ndatabase location by default to be `/var/lib/geocoder-us/geocoder.db`. If you\nhave an EBS volume containing a file called `geocoder.db`, for example, you can\njust mount the volume at `/var/lib/geocoder-us` and then start the server and\nall will be well.\n"
  },
  {
    "path": "debian/changelog",
    "content": "geocoder-us (2.0.1pre-1sg66) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Remove \"la\" from feature type affixes, because it probably is used\n    less frequently then \"La\" as part of a Spanish place name.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Sat, 18 Jun 2011 19:06:47 +0000\n\ngeocoder-us (2.0.1pre-1sg65) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Fix a bug in edge interpolation caused by zero-length segments.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 16 Jun 2011 22:18:47 +0000\n\ngeocoder-us (2.0.1pre-1sg64) lucid; urgency=low\n\n  [ Paul Lathrop ]\n  * Fix upstart job.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Wed, 08 Jun 2011 23:57:47 +0000\n\ngeocoder-us (2.0.1pre-1sg63) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Remove Timeout block from geocode endpoint for being generally\n    unsafe. The timeout can happen elsewhere (e.g. Unicorn or Gate).\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Wed, 08 Jun 2011 22:45:46 +0000\n\ngeocoder-us (2.0.1pre-1sg62) lucid; urgency=low\n\n  [ Paul Lathrop ]\n  * Load the geocoder database location from the env first, then argv.\n    This is not optimal, because it makes sense to have the command-line\n    over-ride the environment, however when we run this under unicorn,\n    argv[0] is set to something that is *not* a database location.\n  * Remove cruft.\n  * Use unicorn to run the geocoder.\n  * Don't run as root.\n  * Reverting \"Remove cruft.\" Resurrect these files I shouldn't have\n    deleted. This reverts commit\n    434f9d3aa40e71a20b5d2cf9b8dad1802282957a.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Wed, 08 Jun 2011 22:10:48 +0000\n\ngeocoder-us (2.0.1pre-1sg61) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Add test for intersections.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Sun, 05 Jun 2011 01:56:46 +0000\n\ngeocoder-us (2.0.1pre-1sg60) lucid; urgency=low\n\n  [ Wade Simmons ]\n  * Revert \"Open a new database connection for every request.\" This\n    reverts commit 5a3e3dd5ea745f15482cb16b28b2d09a6753710d.\n\n  [ Wade Simmons and Derek Smith ]\n  * don't swallow exceptions when creating/destroying temporary\n    databases\n  * ensure that all prepared statements are closed, and make sure the\n    temporary databases are cleaned up if there is an exception\n  * add a TODO to possibly remove the Timeout.timeout\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Sun, 05 Jun 2011 01:35:46 +0000\n\ngeocoder-us (2.0.1pre-1sg59) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Fix missing require timeout?\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 03 Jun 2011 22:57:47 +0000\n\ngeocoder-us (2.0.1pre-1sg58) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Open a new database connection for every request.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 03 Jun 2011 22:49:47 +0000\n\ngeocoder-us (2.0.1pre-1sg57) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Replace thin configs (undoing commit\n    2bd5dd8e9ae5210cd19692a4dfc557129ef07f58)\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 03 Jun 2011 22:40:48 +0000\n\ngeocoder-us (2.0.1pre-1sg56) lucid; urgency=low\n\n  [ Paul Lathrop ]\n  * Fix upstart script so it creates a pidfile.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Wed, 25 May 2011 21:40:46 +0000\n\ngeocoder-us (2.0.1pre-1sg55) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Bug fix the previous commit.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 20 May 2011 00:32:48 +0000\n\ngeocoder-us (2.0.1pre-1sg54) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Don't cache statements anymore.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 20 May 2011 00:18:47 +0000\n\ngeocoder-us (2.0.1pre-1sg53) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Update metaphones in place table.\n  * All tests now pass.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Mon, 16 May 2011 20:59:37 +0000\n\ngeocoder-us (2.0.1pre-1sg52) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Update tiger_import for TIGER/Line 2010.\n  * Remove obvious place duplicates.\n  * Update places for 2010 using TIGER/Line and Geonames.\n  * Final update to new place database.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Mon, 16 May 2011 19:34:35 +0000\n\ngeocoder-us (2.0.1pre-1sg51) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Try moving the temporary intersection table into a separate in-\n    memory database to eliminate locking contention.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 12 May 2011 19:17:24 +0000\n\ngeocoder-us (2.0.1pre-1sg50) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Tue, 03 May 2011 00:09:08 +0000\n\ngeocoder-us (2.0.1pre-1sg49) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 15 Apr 2011 21:31:56 +0000\n\ngeocoder-us (2.0.1pre-1sg48) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Tue, 05 Apr 2011 23:21:46 +0000\n\ngeocoder-us (2.0.1pre-1sg47) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Slightly better: Explicitly close statements on the temporary\n    intersection table to release locks. Also checked cached statements\n    to see if they've been closed. This (hopefully) eliminates the need\n    to flush all statements after the table alteration.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Tue, 05 Apr 2011 18:24:10 +0000\n\ngeocoder-us (2.0.1pre-1sg46) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Oh, and trap SQLite3::LockedException, because maybe that'll\n    magically fix it.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Tue, 05 Apr 2011 18:06:09 +0000\n\ngeocoder-us (2.0.1pre-1sg45) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Throw a few more flush_statements in, because the call to DROP TABLE\n    seems to be wedging on \"database table is locked\" though who alone\n    knows why. Stupid SQLite. Grr.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Tue, 05 Apr 2011 17:51:10 +0000\n\ngeocoder-us (2.0.1pre-1sg44) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Tue, 29 Mar 2011 23:53:42 +0000\n\ngeocoder-us (2.0.1pre-1sg43) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Fix a weird race condition when geocoding intersections.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 17 Feb 2011 22:11:48 +0000\n\ngeocoder-us (2.0.1pre-1sg42) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Break tests to demonstrate Brooklyn/Manhattan regression.\n  * Fix Brooklyn/Manhattan regression. Hooray, test-driven development!\n  * Fix the \"Mountain View, CA\" bug where \"normalizing\" a street type in\n    a city name would prevent the city from getting removed from the\n    street parts in Address.city=.\n  * Add more tests to cover recent bugs.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Wed, 09 Feb 2011 22:37:07 +0000\n\ngeocoder-us (2.0.1pre-1sg41) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Remove \"Brooklyn, NY\" as a place for ZIP 14729. Because that's\n    plainly WRONG.\n  * Pretty print output from CLI demo.\n  * Make all tests pass, post street side offset.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 04 Feb 2011 00:34:10 +0000\n\ngeocoder-us (2.0.1pre-1sg39) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Fix a NaN bug caused by some TIGER/Line from/to house numbers being\n    equal.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Wed, 12 Jan 2011 02:30:40 +0000\n\ngeocoder-us (2.0.1pre-1sg38) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Don't run directly through thin; this causes segfaults on our Debian\n    systems.\n  * Remove thin configs.\n  * Go back to using embedded metaphone function, which will improve\n    result quality.\n  * Move the database open back out to the init step.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Wed, 12 Jan 2011 02:00:40 +0000\n\ngeocoder-us (2.0.1pre-1sg37) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Tue, 04 Jan 2011 19:24:45 +0000\n\ngeocoder-us (2.0.1pre-1sg36) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 23 Dec 2010 17:46:19 +0000\n\ngeocoder-us (2.0.1pre-1sg35) lucid; urgency=low\n\n  [ dsmith ]\n  * Added a health endpoint to the geocoder\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Mon, 20 Dec 2010 19:08:59 +0000\n\ngeocoder-us (2.0.1pre-1sg34) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Mon, 20 Dec 2010 17:39:41 +0000\n\ngeocoder-us (2.0.1pre-1sg33) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Add street-side offsets of 7.5m by default.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Mon, 29 Nov 2010 23:12:51 +0000\n\ngeocoder-us (2.0.1pre-1sg32) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Wed, 24 Nov 2010 22:20:44 +0000\n\ngeocoder-us (2.0.1pre-1sg31) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Mon, 15 Nov 2010 19:35:15 +0000\n\ngeocoder-us (2.0.1pre-1sg29) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Tue, 09 Nov 2010 21:28:24 +0000\n\ngeocoder-us (2.0.1pre-1sg29) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Refactor rest.rb slightly for speed?\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 04 Nov 2010 21:54:45 +0000\n\ngeocoder-us (2.0.1pre-1sg28) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * All-singing, all-dancing REST server.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 04 Nov 2010 19:18:25 +0000\n\ngeocoder-us (2.0.1pre-1sg27) lucid; urgency=low\n\n  [ Schuyler Erle ]\n  * Work around for segfaults in the Metaphone C code.\n  * Add Upstart config.\n  * Remove default and init script, start/stop in postinst/prerm.\n  * Fix up prerm and postinst scripts.\n  * Don't daemonize when running with Upstart.\n  * Tweak respawn rate.\n  * Load a new database handle on every request. Hrrr.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 04 Nov 2010 18:50:00 +0000\n\ngeocoder-us (2.0.1pre-1sg21) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 01 Oct 2010 22:27:07 +0000\n\ngeocoder-us (2.0.1pre-1sg21) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 01 Oct 2010 22:21:08 +0000\n\ngeocoder-us (2.0.1pre-1sg21) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 01 Oct 2010 22:12:09 +0000\n\ngeocoder-us (2.0.1pre-1sg21) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 01 Oct 2010 21:52:07 +0000\n\ngeocoder-us (2.0.1pre-1sg21) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 01 Oct 2010 21:18:23 +0000\n\ngeocoder-us (2.0.1pre-1sg20) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 01 Oct 2010 21:07:24 +0000\n\ngeocoder-us (2.0.1pre-1sg19) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 01 Oct 2010 20:57:25 +0000\n\ngeocoder-us (2.0.1pre-1sg18) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 01 Oct 2010 20:45:23 +0000\n\ngeocoder-us (2.0.1pre-1sg17) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 01 Oct 2010 20:35:26 +0000\n\ngeocoder-us (2.0.1pre-1sg16) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 01 Oct 2010 20:24:24 +0000\n\ngeocoder-us (2.0.1pre-1sg15) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Fri, 01 Oct 2010 20:12:32 +0000\n\ngeocoder-us (2.0.1pre-1sg14) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 30 Sep 2010 22:18:36 +0000\n\ngeocoder-us (2.0.1pre-1sg13) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 30 Sep 2010 22:07:45 +0000\n\ngeocoder-us (2.0.1pre-1sg12) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 30 Sep 2010 21:56:56 +0000\n\ngeocoder-us (2.0.1pre-1sg11) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 30 Sep 2010 21:30:13 +0000\n\ngeocoder-us (2.0.1pre-1sg10) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 30 Sep 2010 20:58:14 +0000\n\ngeocoder-us (2.0.1pre-1sg9) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 30 Sep 2010 19:16:45 +0000\n\ngeocoder-us (2.0.1pre-1sg3) lucid; urgency=low\n\n  * UNRELEASED\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Thu, 30 Sep 2010 18:49:24 +0000\n\ngeocoder-us (2.0.1pre-1sg2) lucid; urgency=low\n\n  [ Ian Eure ]\n  * Build the SQLite extension.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Tue, 24 Aug 2010 20:39:11 +0000\n\ngeocoder-us (2.0.1pre-1sg1) lucid; urgency=low\n\n  [ Ian Eure ]\n  * Add source format.\n  * Build-depend on ruby1.8, build with CDBS, update standards-version.\n  * Strip +x bit from stuff that doesn't need it.\n  * Update copyright.\n  * Update mainteiners, fix section, add .\n  * Fix installation of  stuff in /var.\n\n  [ SimpleGeo Nerds ]\n\n -- SimpleGeo Nerds <nerds@simplegeo.com>  Tue, 24 Aug 2010 02:33:44 +0000\n\ngeocoder-us (2.0.1pre-1sg0) unstable; urgency=low\n\n  * Initial release\n\n -- Schuyler Erle <schuyler@simplegeo.com>  Sat, 07 Aug 2010 00:51:40 +0000\n"
  },
  {
    "path": "debian/compat",
    "content": "7\n"
  },
  {
    "path": "debian/control",
    "content": "Source: geocoder-us\nSection: ruby\nPriority: extra\nMaintainer: SimpleGeo Nerds <nerds@simplegeo.com>\nUploaders: Schuyler Erle <schuyler@simplegeo.com>\nBuild-Depends: debhelper (>= 7), libsqlite3-dev, ruby1.8, cdbs, ruby-pkg-tools\nStandards-Version: 3.8.4\nHomepage: http://github.com/simplegeo/geocoder/\n\nPackage: geocoder-us\nArchitecture: any\nDepends: ${misc:Depends}, ${shlibs:Depends}, ruby1.8, libsqlite3-ruby (>= 1.3.0), libsinatra-ruby, libjson-ruby, unicorn\nDescription: A US address geocoder.\n A US address geocoder. Requires a suitable database.\n"
  },
  {
    "path": "debian/copyright",
    "content": "This work was packaged for Debian by:\n\n    Schuyler Erle <schuyler@simplegeo.com> on Sat, 07 Aug 2010 00:51:40 +0000\n\nIt was downloaded from http://github.com/simplegeo/geocoder/\n\nUpstream Author(s):\n\n    Schuyler Erle <schuyler@simplegeo.com>\n\nCopyright:\n\n    (c) 2009 FortiusOne, Inc.\n\nLicense:\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This package is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\nThe Debian packaging is:\n\n    Copyright (C) 2010 SimpleGeo, Inc.\n\nand is licensed under the GPL version 3, see `/usr/share/common-licenses/GPL-3'.\n"
  },
  {
    "path": "debian/default",
    "content": "# Defaults for geocoder-us upstart job\n# sourced by /etc/init/geocoder-us.conf\n# installed at /etc/default/geocoder-us by maintainer scripts\n\n# Set the location of the geocoder database.\nexport GEOCODER_DB=\"/var/lib/geocoder-us/geocoder.db\"\n"
  },
  {
    "path": "debian/docs",
    "content": "History.txt\nManifest.txt\nREADME.rdoc\nTODO.txt\nTODO.txt\n"
  },
  {
    "path": "debian/geocoder-us.postinst",
    "content": "#!/bin/sh\n# postinst script for #PACKAGE#\n#\n# see: dh_installdeb(1)\n\nset -e\n\n# summary of how this script can be called:\n#        * <postinst> `configure' <most-recently-configured-version>\n#        * <old-postinst> `abort-upgrade' <new version>\n#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>\n#          <new-version>\n#        * <postinst> `abort-remove'\n#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'\n#          <failed-install-package> <version> `removing'\n#          <conflicting-package> <version>\n# for details, see http://www.debian.org/doc/debian-policy/ or\n# the debian-policy package\n\n\ncase \"$1\" in\n    configure)\n         # just make sure that /usr/bin/thin can write its PID file and logs\n         chown www-data /var/run/geocoder-us\n         chown www-data /var/log/geocoder-us\n         start geocoder-us || /bin/true\n    ;;\n\n    abort-upgrade|abort-remove|abort-deconfigure)\n    ;;\n\n    *)\n        echo \"postinst called with unknown argument \\`$1'\" >&2\n        exit 1\n    ;;\nesac\n\n# dh_installdeb will replace this with shell code automatically\n# generated by other debhelper scripts.\n\n#DEBHELPER#\n\nexit 0\n"
  },
  {
    "path": "debian/geocoder-us.prerm",
    "content": "#!/bin/sh\n\nset -e\n\ncase \"$1\" in\n    remove|deconfigure)\n        stop geocoder-us || true\n        ;;\n    upgrade)\n        ;;\n    failed-upgrade)\n        ;;\n    *)\n        echo \"prerm called with unknown argument \\`$1'\" >&2\n        exit 0\n    ;;\nesac\n\n# dh_installdeb will replace this with shell code automatically\n# generated by other debhelper scripts.\n\n\n\nexit 0\n"
  },
  {
    "path": "debian/rules",
    "content": "#!/usr/bin/make -f\n\ninclude /usr/share/cdbs/1/rules/debhelper.mk\ninclude /usr/share/ruby-pkg-tools/1/class/ruby-setup-rb.mk\n\n\n# Add here any variable or target overrides you need.\n\nbuild/geocoder-us::\n\tmake -C $(CURDIR)/src/libsqlite3_geocoder\n\tinstall -m 0644 $(CURDIR)/src/libsqlite3_geocoder/*.so \\\n\t$(CURDIR)/lib/geocoder/us/sqlite3.so\n\ninstall/geocoder-us::\n\tinstall -d -m 0755 $(DEB_DESTDIR)var/lib/geocoder-us \\\n\t\t$(DEB_DESTDIR)var/run/geocoder-us \\\n\t\t$(DEB_DESTDIR)var/log/geocoder-us\n\n"
  },
  {
    "path": "debian/source/format",
    "content": "3.0 (quilt)\n"
  },
  {
    "path": "demos/api/server.rb",
    "content": "require 'rubygems'\nrequire 'sinatra'\nrequire 'geocoder/us/database'\nrequire 'json'\n\nset :port, 8080\n@@db = Geocoder::US::Database.new(\"/home/sderle/geocoder/california.db\")\nget '/geocode.json' do\n  if params[:q]\n    (@@db.geocode params[:q]).to_json\n  else\n    status 400\n    \"parameter 'q' is missing\"\n  end\nend\nget '/' do\n  unless params[:q].nil?\n    @records = @@db.geocode params[:q]\n  end\n  erb :index\nend\n"
  },
  {
    "path": "demos/api/views/index.erb",
    "content": "<!DOCTYPE html\n    PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n<head>\n    <style type=\"text/css\">\n    html {font-family: Arial, sans-serif;}\n    table {font-size: 8pt; border-collapse: collapse;}\n    td { border: 1px solid black; padding: .25em .5em .25em .5em; }\n    </style>\n</head>\n<body onload=\"\">\n  <p><b>Geocoder Demo</b></p>\n  <p>\n    <form method=\"GET\">\n      <label>Enter an address:</label> <input type=\"text\" name=\"q\" value=\"<%= params[:q] %>\" size=\"80\">\n      <input type=\"hidden\" name=\"f\" value=\"html\" />\n      <input type=\"submit\" value=\"Geocode\" />\n    </form>\n  </p>\n  <% unless @records.nil? %>\n  <table>\n    <tr>\n      <td>Match</td>\n      <td>Lat</td>\n      <td>Lon</td>\n      <td>#</td>\n      <td>Qual</td>\n      <td>Dir</td>\n      <td>Type</td>\n      <td>Street</td>\n      <td>Type</td>\n      <td>Dir</td>\n      <td>Qual</td>\n      <td>City</td>\n      <td>St</td>\n      <td>ZIP</td>\n      <td>&nbsp;</td>\n    </tr>\n    <% for record in @records %>\n    <tr>\n      <td><%= format(\"%.2f\", record[:score]*100) %>%</td>\n      <td><%= record[:lat].to_s %></td>\n      <td><%= record[:lon].to_s %></td>\n      <td><%= record[:prefix] if record[:prefix] %><%= record[:number] %></td>\n      <td><%= record[:pretyp] %></td>\n      <td><%= record[:predir] %></td>\n      <td><%= record[:prequal] %></td>\n      <td><%= record[:street] %></td>\n      <td><%= record[:suftyp] %></td>\n      <td><%= record[:sufdir] %></td>\n      <td><%= record[:sufqual] %></td>\n      <td><%= record[:city] %></td>\n      <td><%= record[:state] %></td>\n      <td><%= record[:zip] %></td>\n      <td><a href=\"http://maps.google.com/maps?q=<%=record[:lat]%>,<%=record[:lon]%>\"\n        target=\"_blank\">map</a></td>\n      </tr>\n      <% end %>\n    </table>\n    <% end %>\n  </body>\n  </html>\n"
  },
  {
    "path": "demos/cli.rb",
    "content": "require 'geocoder/us/database'\nrequire 'pp'\n\ndb = Geocoder::US::Database.new(\"/mnt/tiger2010/geocoder.db\", :debug=>true)\nresult = db.geocode(ARGV[0])\npp(result)\nprint \"#{result[0][:lat]} N, #{-result[0][:lon]} W\\n\"\n"
  },
  {
    "path": "demos/demo/app/ext/geocodewrap.rb",
    "content": "require 'rubygems'\nrequire 'geocoder/us/database'\nrequire 'logger'\n\nmodule Sinatra\n  module GeocodeWrap\n    attr_accessor :db\n    def self.registered(app)\n      options = {:cache_size => 100000}\n       @@db = Geocoder::US::Database.new(\"/Users/katechapman/usgeocode.db\", options)\n       stats = Logger.new(\"geocoderstats.log\", 10, 1024000)\n       app.get '/' do\n     \t   unless params[:address].nil?\n           begin\n             @records = @@db.geocode params[:address]\n             stats.debug \"Geocoded: 1, Failed: 0, Geocoded At: \" << DateTime.now.to_s\n   \t       rescue Exception => e\n   \t         stats.debug \"Geocoded: 1, Failed: 1, Geocoded At: \" << DateTime.now.to_s\n   \t         puts e.message\n   \t       end\n   \t      end\n\n\t        case params[:format]\n\t        when /xml/\n\t          builder :index\n\t        when /atom/\n\t          builder :atom\n\t        when /json/\n\t          @records.to_json\n \t        else\n\t          erb :index\n\t        end\n        end\n       \n       app.post '/batch' do\n         failed_codes = 0\n         total_codes = 0\n         puts Time.now\n       \tif params[:uploaded_csv].nil?\n          csv_file = request.env[\"rack.input\"].read\n       \t  csv = FasterCSV.parse(csv_file, :row_sep => \"*\", :col_sep => \"|\")\n       else \n       \t  FileUtils.mkdir_p('uploads/')\n          FileUtils.mv(params[:uploaded_csv][:tempfile].path, \"uploads/#{params[:uploaded_csv][:filename]}\")  \n          csv_file = open(\"uploads/#{params[:uploaded_csv][:filename]}\")\n          @filename = params[:uploaded_csv][:filename].gsub(/\\.csv/,\"\")\n          csv = FasterCSV.parse(csv_file)\n       end\n       \t  headers = csv[0]\n       \t \n       \t  @records = csv.collect do |record|\n       \t    total_codes += 1\n       \t  next if record == headers\n            begin\n       \t      result = @@db.geocode record[1]\n       \t      if result.empty?\n       \t         result[0] = {:lon => nil, :lat => nil, :precision => 'unmatched', :score => 0}   \n       \t         failed_codes += 1 \n       \t      end\n       \t      result.first.merge(headers[0] => record[0])\n            rescue Exception => e\n              failed_codes += 1 \n       \t      puts e.message\n              next\n       \t     end\n             end.compact\n            puts Time.now\n            stats.debug \"Geocoded: \" << total_codes.to_s << \", Failed: \" << failed_codes.to_s << \",Geocoded At: \" << DateTime.now.to_s\n            case params[:format]\n       \t    when /xml/\n       \t     builder :index\n       \t    when /atom/\n       \t     builder :atom\n       \t    when /json/\n       \t     @records.to_json\n       \t     \n       \t    else\n       \t     erb :index\n       \t    end \n          end\n        end\n      end\n  register GeocodeWrap\nend\n"
  },
  {
    "path": "demos/demo/app/views/index.builder",
    "content": "xml.locations do\n  unless @records.nil?\n    @records.each do |record|\n      xml.location do\n        xml.score format(\"%.2f\", record[:score]*100)\n        %w{lat lon number prefix pretyp predir prequal street suftyp sufdir sufqual city state zip}.each do |field|\n          xml.tag! field, record[field.to_sym]\n        end\n      end\n    end\n  end\nend\n\n"
  },
  {
    "path": "demos/demo/app/views/index.erb",
    "content": "<!DOCTYPE html\n    PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n<head>\n    <style type=\"text/css\">\n    html {font-family: Arial, sans-serif;}\n    table {font-size: 8pt; border-collapse: collapse;}\n    td { border: 1px solid black; padding: .25em .5em .25em .5em; }\n    </style>\n</head>\n<body onload=\"\">\n  <p><b>Geocoder Demo</b></p>\n  <p>\n    <form>\n      <label>Enter an address:</label> <input type=\"text\" name=\"address\" value=\"<%= params[:address] %>\" size=\"80\">\n      <input type=\"submit\" value=\"Geocode\" />\n    </form>\n    <form action=\"batch\" method=\"POST\" enctype=\"multipart/form-data\" accept-charset=\"utf-8\">\n      <label>Upload a CSV:</label> <input type=\"file\" name=\"uploaded_csv\" id=\"uploaded_csv\">\n      <input type=\"submit\" value=\"Batch Geocode\" />\n    </form>\n  </p>\n  <% unless @records.nil? %>\n  <table>\n    <tr>\n      <td>Match</td>\n      <td>Precision</td>\n      <td>Lat</td>\n      <td>Lon</td>\n      <td>#</td>\n      <td>Qual</td>\n      <td>Dir</td>\n      <td>Type</td>\n      <td>Street</td>\n      <td>Type</td>\n      <td>Dir</td>\n      <td>Qual</td>\n      <td>City</td>\n      <td>St</td>\n      <td>ZIP</td>\n      <td>&nbsp;</td>\n    </tr>\n    <% for record in @records %>\n    <tr>\n      <td><%= format(\"%.2f\", record[:score]*100) %>%</td>\n      <td><%= record[:precision].to_s %></td>\n      <td><%= record[:lat].to_s %></td>\n      <td><%= record[:lon].to_s %></td>\n      <td><%= record[:prefix] if record[:prefix] %><%= record[:number] %></td>\n      <td><%= record[:pretyp] %></td>\n      <td><%= record[:predir] %></td>\n      <td><%= record[:prequal] %></td>\n      <td><%= record[:street] %></td>\n      <td><%= record[:suftyp] %></td>\n      <td><%= record[:sufdir] %></td>\n      <td><%= record[:sufqual] %></td>\n      <td><%= record[:city] %></td>\n      <td><%= record[:state] %></td>\n      <td><%= record[:zip] %></td>\n      <td><a href=\"http://maps.google.com/maps?q=<%=record[:lat]%>,<%=record[:lon]%>\"\n        target=\"_blank\">map</a></td>\n      </tr>\n      <% end %>\n    </table>\n    <% end %>\n    <% unless @filename.nil? %>\n     <a href=\"/link.atom?filename=<%= @filename %>\">Atom Feed</a>\n   <% end %>\n  </body>\n  </html>\n"
  },
  {
    "path": "demos/demo/config/bootstraps.rb",
    "content": "require 'rubygems'\n\nmodule BootStraps\n\n  class Framework \n\n    def initialize \n      @methods = {}\n    end\n    \n    def apply_settings!(app)\n      @methods.each_pair do |method, calls|\n        calls.each do |arg_set|\n          app.send(method, *arg_set)\n        end\n      end\n    end\n    \n    def method_missing(method, *args)\n      @methods[method] ||= []\n      @methods[method] << args\n    end\n  end\n\n\n  class DataStore \n    def connect_action(&block)\n      @connect_action = block\n    end\n\n    #TODO raise UndefinedConnectAction\n    def connect\n      @connect_action.call if @connect_action\n    end\n  end\n  \n  class Configuration\n    attr_accessor :db, :global, :default_env, :vendor_dir, :lib_paths, :framework, :vendored\n    attr_reader :gems\n\n    def initialize\n      @framework = Framework.new\n      @gems = {}\n      @global = {}\n      @default_env = 'production'\n      @vendor_dir = File.join(root, 'vendor')\n      @lib_paths = []\n      @vendored = false\n    end\n\n    def env \n      ENV['RACK_ENV'] ||= default_env \n    end\n    \n    def env=(val)\n      ENV['RACK_ENV'] = val\n    end\n\n    def root\n      File.join(File.expand_path(File.dirname(__FILE__)), \"..\")\n    end\n    \n    def gem(*args)\n      gem = args.first\n      ver = args.last\n\n      @gems[gem] = ver\n        \n      #its concievable that vendored could be changed mid config\n      use_vendor if vendored\n      Kernel.send(:gem, *args)\n      require gem\n    end\n\n    private\n    def use_vendor\n      Gem.clear_paths\n      prepend_gem_path!(File.join(root, 'vendor'))\n    end\n    \n    def prepend_gem_path!(path)\n      ENV['GEM_PATH'] = path\n    end  \n  end\n\n  class Initializer\n    @@config = Configuration.new\n    class << self\n      def configure\n        unless @@config.frozen?\n          yield @@config\n          @@config.freeze\n        end\n      end\n\n      def config\n        @@config\n      end \n      \n      def boot!\n        require File.join(@@config.root, 'config', 'geoenvironment.rb')\n        require_libs\n      end\n\n\n      private      \n      def require_libs\n        [\n         subdir_expansion('lib'), \n         subdir_expansion(File.join('app','ext'))\n        ].each do |p|\n          require_all(p)\n        end\n      end\n\n      def require_all(path)\n        Dir[path].each { |f| require f }\n      end \n\n      def subdir_expansion(subdir)\n        File.join(@@config.root, subdir, '**', '*.rb')\n      end\n    end\n  end\nend\n\nBootStraps::Initializer.boot!\nStraps = BootStraps::Initializer.config\n\n\n"
  },
  {
    "path": "demos/demo/config/geoenvironment.rb",
    "content": "\nBootStraps::Initializer.configure do |config|\n  \n  #Use the vendor directory\n  config.vendored = true\n  config.default_env = 'production'\n  \n  config.gem 'sinatra'\n  config.gem 'fastercsv'\n  config.gem 'json'\n  \n  \n\n\n  config.framework.set :root, config.root\n  config.framework.set :environment, config.env\n  config.framework.set :raise_errors, true\n  config.framework.set :views, File.join('app','views')\n  config.framework.set :server, 'mongrel'\n  config.framework.set :static, true\n  config.framework.set :logging, true\n  config.framework.set :port, 4567\n  config.framework.set :lock, false  \n\nend\n"
  },
  {
    "path": "demos/demo/config.ru",
    "content": "require 'rubygems'\nrequire 'sinatra'\n\n\nSinatra::Application.default_options.merge!(\n :run => false,\n :env => ENV['RACK_ENV']\n)\nrequire 'geocom_geocode'\nrun GeocomGeocode::GeocodeServer\n\n\n"
  },
  {
    "path": "demos/demo/geocoder_helper.rb",
    "content": "require 'rubygems'\nrequire 'geocoder/us/database'\nrequire 'fastercsv'\nrequire 'json'\n\n\n\ndef initialize\n\n\n\nend\n"
  },
  {
    "path": "demos/demo/geocom_geocode.rb",
    "content": "require 'config/bootstraps'\n\nmodule GeocomGeocode\n  class GeocodeServer < Sinatra::Base\n    register Sinatra::GeocodeWrap  \n    configure do\n      Straps.framework.apply_settings!(self)\n    end \n  end\nend\n"
  },
  {
    "path": "demos/demo/main.rb",
    "content": "require 'geocom_geocode'\n\nGeocomGeocode::GeocodeServer.run!\n"
  },
  {
    "path": "demos/demo/rakefile.rb",
    "content": "require 'rake'\n\ntask :boot_env do \n  require 'config/bootstraps'; \nend\n\nnamespace :db do\n  task :migrate => :connect do\n    ActiveRecord::Base.logger = Logger.new(STDOUT)\n    ActiveRecord::Migration.verbose = true\n    ActiveRecord::Migrator.migrate('db/migrate/', nil)\n  end\n  \n  task :connect => :boot_env do\n    BootStraps::Initializer.config.db.connect\n  end\nend"
  },
  {
    "path": "demos/demo/tmp/restart.txt",
    "content": ""
  },
  {
    "path": "demos/parse.rb",
    "content": "require 'geocoder/us/address'\nrequire 'pp'\n\npp(Geocoder::US::Address.new(ARGV[0]))\n"
  },
  {
    "path": "demos/simpledemo/views/index.builder",
    "content": "xml.locations do\n  unless @records.nil?\n    @records.each do |record|\n      xml.location do\n        xml.score format(\"%.2f\", record[:score]*100)\n        %w{lat lon number prefix pretyp predir prequal street suftyp sufdir sufqual city state zip}.each do |field|\n          xml.tag! field, record[field.to_sym]\n        end\n      end\n    end\n  end\nend\n\n"
  },
  {
    "path": "demos/simpledemo/views/index.erb",
    "content": "<!DOCTYPE html\n    PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n<head>\n    <style type=\"text/css\">\n    html {font-family: Arial, sans-serif;}\n    table {font-size: 8pt; border-collapse: collapse;}\n    td { border: 1px solid black; padding: .25em .5em .25em .5em; }\n    </style>\n</head>\n<body onload=\"\">\n  <p><b>Geocoder Demo</b></p>\n  <p>\n    <form>\n      <label>Enter an address:</label> <input type=\"text\" name=\"address\" value=\"<%= params[:address] %>\" size=\"80\">\n      <input type=\"submit\" value=\"Geocode\" />\n    </form>\n    <form action=\"batch\" method=\"POST\" enctype=\"multipart/form-data\" accept-charset=\"utf-8\">\n      <label>Upload a CSV:</label> <input type=\"file\" name=\"uploaded_csv\" id=\"uploaded_csv\">\n      <input type=\"submit\" value=\"Batch Geocode\" />\n    </form>\n  </p>\n  <% unless @records.nil? %>\n  <table>\n    <tr>\n      <td>Match</td>\n      <td>Lat</td>\n      <td>Lon</td>\n      <td>#</td>\n      <td>Qual</td>\n      <td>Dir</td>\n      <td>Type</td>\n      <td>Street</td>\n      <td>Type</td>\n      <td>Dir</td>\n      <td>Qual</td>\n      <td>City</td>\n      <td>St</td>\n      <td>ZIP</td>\n      <td>&nbsp;</td>\n    </tr>\n    <% for record in @records %>\n    <tr>\n      <td><%= format(\"%.2f\", record[:score]*100) %>%</td>\n      <td><%= record[:lat].to_s %></td>\n      <td><%= record[:lon].to_s %></td>\n      <td><%= record[:prefix] if record[:prefix] %><%= record[:number] %></td>\n      <td><%= record[:pretyp] %></td>\n      <td><%= record[:predir] %></td>\n      <td><%= record[:prequal] %></td>\n      <td><%= record[:street] %></td>\n      <td><%= record[:suftyp] %></td>\n      <td><%= record[:sufdir] %></td>\n      <td><%= record[:sufqual] %></td>\n      <td><%= record[:city] %></td>\n      <td><%= record[:state] %></td>\n      <td><%= record[:zip] %></td>\n      <td><a href=\"http://maps.google.com/maps?q=<%=record[:lat]%>,<%=record[:lon]%>\"\n        target=\"_blank\">map</a></td>\n      </tr>\n      <% end %>\n    </table>\n    <% end %>\n    <% unless @filename.nil? %>\n     <a href=\"/link.atom?filename=<%= @filename %>\">Atom Feed</a>\n   <% end %>\n  </body>\n  </html>\n"
  },
  {
    "path": "demos/simpledemo/ws.rb",
    "content": "require 'rubygems'\nrequire 'sinatra'\nrequire 'geocoder/us/database'\nrequire 'fastercsv'\nrequire 'json'\n\nset :port, 8080\n@@db = Geocoder::US::Database.new(\"/fortiusone/geocoder/geocoder.db\")\nget '/' do\n  unless params[:address].nil?\n    @records = @@db.geocode params[:address]\n  end\n\n  case params[:format]\n  when /xml/\n    builder :index\n  when /atom/\n    builder :atom\n  else\n    erb :index\n  end\nend\n\nrequire 'open-uri'\nget '/link.:format' do \n  if(params.include?(:url))\n\tcsv_file = params[:url]\n  else\n  csv_file = \"uploads/#{params[:filename]}.csv\"\nend\n  csv = FasterCSV.parse(open(csv_file))\n  headers = csv[0]\n  \n  @records = csv.collect do |record|\n    next if record == headers\n    begin\n      (@@db.geocode record[1]).first\n    rescue Exception => e\n      puts e.message\n      next\n    end\n  end.compact\n  case params[:format]\n  when /atom/\n    builder :atom\n  when /xml/\n    builder :index\n  else\n    erb :index\n  end\n  \nend\n\n\npost '/batch' do \n  csv_file = request.env[\"rack.input\"].read\n  csv = FasterCSV.parse(csv_file, :row_sep => \"*\", :col_sep => \"|\")\n  headers = csv[0]\n  @records = csv.collect do |record|\n  next if record == headers\n    begin\n      (@@db.geocode record[1]).first.merge(headers[0] => record[0])\n    rescue Exception => e\n      puts e.message\n    next\n    end\n     end.compact\n  case params[:format]\n  when /xml/\n    builder :index\n  when /atom/\n    builder :atom  \n  when /json/\n    @records.to_json\n  else\n    erb :index\n  end\nend\n\n  \n\n\n\n"
  },
  {
    "path": "doc/Makefile",
    "content": "all: lookup.html parsing.html\n\n%.html: %.rst voidspace.css\n\trst2html --stylesheet-path=voidspace.css --no-compact-lists $< > $@\n\nclean:\n\trm -f *.html\n"
  },
  {
    "path": "doc/html4css1.css",
    "content": "/*\n:Author: David Goodger\n:Contact: goodger@users.sourceforge.net\n:Date: $Date: 2005-12-18 01:56:14 +0100 (Sun, 18 Dec 2005) $\n:Revision: $Revision: 4224 $\n:Copyright: This stylesheet has been placed in the public domain.\n\nDefault cascading style sheet for the HTML output of Docutils.\n\nSee http://docutils.sf.net/docs/howto/html-stylesheets.html for how to\ncustomize this style sheet.\n*/\n\n/* used to remove borders from tables and images */\n.borderless, table.borderless td, table.borderless th {\n  border: 0 }\n\ntable.borderless td, table.borderless th {\n  /* Override padding for \"table.docutils td\" with \"! important\".\n     The right padding separates the table cells. */\n  padding: 0 0.5em 0 0 ! important }\n\n.first {\n  /* Override more specific margin styles with \"! important\". */\n  margin-top: 0 ! important }\n\n.last, .with-subtitle {\n  margin-bottom: 0 ! important }\n\n.hidden {\n  display: none }\n\na.toc-backref {\n  text-decoration: none ;\n  color: black }\n\nblockquote.epigraph {\n  margin: 2em 5em ; }\n\ndl.docutils dd {\n  margin-bottom: 0.5em }\n\n/* Uncomment (and remove this text!) to get bold-faced definition list terms\ndl.docutils dt {\n  font-weight: bold }\n*/\n\ndiv.abstract {\n  margin: 2em 5em }\n\ndiv.abstract p.topic-title {\n  font-weight: bold ;\n  text-align: center }\n\ndiv.admonition, div.attention, div.caution, div.danger, div.error,\ndiv.hint, div.important, div.note, div.tip, div.warning {\n  margin: 2em ;\n  border: medium outset ;\n  padding: 1em }\n\ndiv.admonition p.admonition-title, div.hint p.admonition-title,\ndiv.important p.admonition-title, div.note p.admonition-title,\ndiv.tip p.admonition-title {\n  font-weight: bold ;\n  font-family: sans-serif }\n\ndiv.attention p.admonition-title, div.caution p.admonition-title,\ndiv.danger p.admonition-title, div.error p.admonition-title,\ndiv.warning p.admonition-title {\n  color: red ;\n  font-weight: bold ;\n  font-family: sans-serif }\n\n/* Uncomment (and remove this text!) to get reduced vertical space in\n   compound paragraphs.\ndiv.compound .compound-first, div.compound .compound-middle {\n  margin-bottom: 0.5em }\n\ndiv.compound .compound-last, div.compound .compound-middle {\n  margin-top: 0.5em }\n*/\n\ndiv.dedication {\n  margin: 2em 5em ;\n  text-align: center ;\n  font-style: italic }\n\ndiv.dedication p.topic-title {\n  font-weight: bold ;\n  font-style: normal }\n\ndiv.figure {\n  margin-left: 2em ;\n  margin-right: 2em }\n\ndiv.footer, div.header {\n  clear: both;\n  font-size: smaller }\n\ndiv.line-block {\n  display: block ;\n  margin-top: 1em ;\n  margin-bottom: 1em }\n\ndiv.line-block div.line-block {\n  margin-top: 0 ;\n  margin-bottom: 0 ;\n  margin-left: 1.5em }\n\ndiv.sidebar {\n  margin-left: 1em ;\n  border: medium outset ;\n  padding: 1em ;\n  background-color: #ffffee ;\n  width: 40% ;\n  float: right ;\n  clear: right }\n\ndiv.sidebar p.rubric {\n  font-family: sans-serif ;\n  font-size: medium }\n\ndiv.system-messages {\n  margin: 5em }\n\ndiv.system-messages h1 {\n  color: red }\n\ndiv.system-message {\n  border: medium outset ;\n  padding: 1em }\n\ndiv.system-message p.system-message-title {\n  color: red ;\n  font-weight: bold }\n\ndiv.topic {\n  margin: 2em }\n\nh1.section-subtitle, h2.section-subtitle, h3.section-subtitle,\nh4.section-subtitle, h5.section-subtitle, h6.section-subtitle {\n  margin-top: 0.4em }\n\nh1.title {\n  text-align: center }\n\nh2.subtitle {\n  text-align: center }\n\nhr.docutils {\n  width: 75% }\n\nimg.align-left {\n  clear: left }\n\nimg.align-right {\n  clear: right }\n\nol.simple, ul.simple {\n  margin-bottom: 1em }\n\nol.arabic {\n  list-style: decimal }\n\nol.loweralpha {\n  list-style: lower-alpha }\n\nol.upperalpha {\n  list-style: upper-alpha }\n\nol.lowerroman {\n  list-style: lower-roman }\n\nol.upperroman {\n  list-style: upper-roman }\n\np.attribution {\n  text-align: right ;\n  margin-left: 50% }\n\np.caption {\n  font-style: italic }\n\np.credits {\n  font-style: italic ;\n  font-size: smaller }\n\np.label {\n  white-space: nowrap }\n\np.rubric {\n  font-weight: bold ;\n  font-size: larger ;\n  color: maroon ;\n  text-align: center }\n\np.sidebar-title {\n  font-family: sans-serif ;\n  font-weight: bold ;\n  font-size: larger }\n\np.sidebar-subtitle {\n  font-family: sans-serif ;\n  font-weight: bold }\n\np.topic-title {\n  font-weight: bold }\n\npre.address {\n  margin-bottom: 0 ;\n  margin-top: 0 ;\n  font-family: serif ;\n  font-size: 100% }\n\npre.literal-block, pre.doctest-block {\n  margin-left: 2em ;\n  margin-right: 2em ;\n  background-color: #eeeeee }\n\nspan.classifier {\n  font-family: sans-serif ;\n  font-style: oblique }\n\nspan.classifier-delimiter {\n  font-family: sans-serif ;\n  font-weight: bold }\n\nspan.interpreted {\n  font-family: sans-serif }\n\nspan.option {\n  white-space: nowrap }\n\nspan.pre {\n  white-space: pre }\n\nspan.problematic {\n  color: red }\n\nspan.section-subtitle {\n  /* font-size relative to parent (h1..h6 element) */\n  font-size: 80% }\n\ntable.citation {\n  border-left: solid 1px gray;\n  margin-left: 1px }\n\ntable.docinfo {\n  margin: 2em 4em }\n\ntable.docutils {\n  margin-top: 0.5em ;\n  margin-bottom: 0.5em }\n\ntable.footnote {\n  border-left: solid 1px black;\n  margin-left: 1px }\n\ntable.docutils td, table.docutils th,\ntable.docinfo td, table.docinfo th {\n  padding-left: 0.5em ;\n  padding-right: 0.5em ;\n  vertical-align: top }\n\ntable.docutils th.field-name, table.docinfo th.docinfo-name {\n  font-weight: bold ;\n  text-align: left ;\n  white-space: nowrap ;\n  padding-left: 0 }\n\nh1 tt.docutils, h2 tt.docutils, h3 tt.docutils,\nh4 tt.docutils, h5 tt.docutils, h6 tt.docutils {\n  font-size: 100% }\n\ntt.docutils {\n  background-color: #eeeeee }\n\nul.auto-toc {\n  list-style-type: none }\n"
  },
  {
    "path": "doc/lookup.rst",
    "content": ".. _lookup:\n\n===================================\nGeocoder.us Address Lookup Strategy\n===================================\n\n:Author: Schuyler Erle\n:Contact: schuyler at geocoder dot us\n:Created: 2009/03/13\n:Edited: 2009/03/14\n\nDefinitions\n-----------\n\nEdge\n  Database representation of a street segment, consisting of a linestring\n  geometry and an edge ID. Edges relate to many ranges and many features\n  through its ID.\n\nFeature\n  Database representation of a named street, consisting of street name\n  and modifier elements, a reference ZIP code, and a primary/alternate flag.\n\nRange\n  Database representation of a range of address numbers on a given\n  street, consisting of range start and end numbers, an optional prefix\n  ending with a non-numeric character, and a delivery ZIP code for that\n  range.\n\nPlace\n  Database representation of a ZIP code, consisting of a city name,\n  state abbreviation, a ZIP code, and a primary/alternate flag.\n\nAddress record\n  A set consisting of exactly one edge, one feature, and one range, related\n  through the edge ID.\n\nAddress query\n  An ordered set of {Number Prefix, Number, Directional Prefix, Type Prefix,\n  Qualifier Prefix, Street Name, Qualifier Suffix, Type Suffix, Directional\n  Suffix, City, State, ZIP}. All of the elements are optional except Number and\n  Street Name. Either ZIP or City must also be present. The State element\n  and all of the prefix and suffix elements are assumed to be normalized to\n  standard postal abbreviations.\n\nAddress string\n  A string including some or all of the elements of an address.\n\nAddress Lookup Strategy\n-----------------------\n\n1. Given a an address query, initialize an empty set of candidate places,\n   and an empty set of candidate address records.\n\n#. If a ZIP was given, look up `the place from the ZIP`_, and add the\n   place, if any, to the candidate place set.\n\n#. If a city was given, look up all `the places matching the metaphone hash\n   of the city name`_, and add them, if any, to the candidate place set.\n\n#. Generate a unique set of ZIPs from the set of candidate places, since a ZIP\n   may have one or more names associated with it.\n\n#. Generate `a list of candidate address records`_ by fetching all the street\n   features matching the metaphone hash of the street name and one of the ZIPs\n   in the query set, along with the ranges matching the edge ID of each\n   feature, where the given number is in the range. The edge does not\n   need to be fetched yet.\n\n#. If the look up generates no results, optionally generate `more candidate\n   records`_ by looking up all the street features matching the metaphone hash\n   of the street name, along with the ranges matching the edge ID of each\n   feature, where the given number is in the range. This may be a very time\n   consuming database query, because some street names are quite common.\n\n#. Score each of the candidate records as follows:\n\n   a. Score one point for every provided element of the address query that it\n      matches exactly. \n   #. Optionally, compute the scaled Damerau-Levenshtein distance (or\n      alternately the simple Levenshtein distance) between each provided\n      element of the address query and the corresponding element in the\n      candidate. Score one minus the scaled distance, which yields a fraction\n      of a point.\n   #. Score one point if the parity of starting range number matches the parity\n      of the queried address number.\n   #. Note that the maximum possible score is equal to the number of provided\n      elements in the address query. Divide the score by the maximum possible.\n      This is the confidence value of the candidate.\n\n#. Sort the candidate address records by confidence. Retain only the records\n   that share the highest confidence as candidates.\n\n#. Fetch `the edges and primary feature names`_ matching the edge IDs of\n   the remaining candidate address records.\n\n#. For each remaining candidate record:\n\n   a. Replace the candidate record feature elements with those of the\n      primary feature name for that edge.\n   #. Fetch `all of the ranges for the edge ID`_ of the candidate, sorted by\n      starting number.\n   #. Compute the sum of the differences of the starting and ending house\n      number for each range. This is the total number width of the edge.\n   #. Take the difference between the candidate starting number and the lowest\n      starting number, add the difference between the queried number and the\n      candidate starting number, and divide by the total number width. This is\n      the interpolation distance.\n   #. Optionally, find the local UTM zone and project the edge into it.\n   #. Find the point along the line at the interpolation distance.\n   #. If the edge was projected, unproject the point.\n   #. Assign the point as the geocoded location of the query to the candidate\n      record.\n\n#. Construct a set of result ZIPs from the remaining candidates, and look up\n   `the primary name and state for each ZIP`_ in the set. Assign the matching\n   primary city and state to each candidate.\n\n#. Return the set of candidate records as the result of the query.\n \nSQL Statements\n--------------\n\nthe place from the ZIP\n~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n    SELECT * FROM place WHERE zip = '...';\n\nthe places matching the metaphone hash of the city name\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n    SELECT * FROM place WHERE city_phone = metaphone('...');\n\na list of candidate address records\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n    SELECT feature.*, range.* FROM feature, range\n        WHERE name_phone = metaphone('...') AND feature.zip IN (...)\n        AND range.tlid = feature.tlid\n        AND fromhn <= ... AND tohn >= ...;\n\nmore candidate records\n~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n    SELECT feature.*, range.* FROM feature, range\n        WHERE name_phone = metaphone('...')\n        AND range.tlid = feature.tlid\n        AND fromhn <= ... AND tohn >= ...;\n\nthe edges and primary feature names\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n    SELECT feature.*, edge.* FROM feature, edge\n        WHERE feature.tlid = ... AND paflag = 'P'\n        AND edge.tlid = feature.tlid;\n\n    -- or\n\n    SELECT feature.*, edge.* FROM feature, edge\n        WHERE feature.tlid IN (...)\n        AND paflag = 'P'\n        AND edge.tlid = feature.tlid;\n\nall of the ranges for the edge ID\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n    SELECT * FROM range WHERE range.tlid = ...;\n\n    -- or\n\n    SELECT * FROM range WHERE range.tlid IN (...);\n\nthe primary name and state for each ZIP\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n\n::\n\n    SELECT * FROM place WHERE zip IN (...) AND paflag = 'P';\n\n= 30 =\n"
  },
  {
    "path": "doc/parsing.rst",
    "content": ".. _parsing:\n\n====================================\nGeocoder.us Address Parsing Strategy\n====================================\n\n:Author: Schuyler Erle\n:Contact: schuyler at geocoder dot us\n:Created: 2009/03/18\n:Edited: 2009/03/18\n\nStructured address components\n-----------------------------\n\nUnless otherwise labeled as \"required\", all components of a structured address\nare optional.\n\nprenum\n    The alphanumeric prefix portion of a house or building number. (e.g. \"32-\"\n    in \"32-20 Jackson St\".\n\nnumber\n    The house or building number component. Required.\n\nsufnum\n    The alphanumeric suffix portion of a house or building number. (e.g. \"23B\n    Baker St\")\n\nfraction\n    The fractional portion of a house or building number. (e.g. \"23 1/2 Baker\n    St\")\n\npredir\n    The prefixed street directional component. (e.g. \"N\", \"SW\")\n\nprequal\n    The prefixed street qualifier component. (e.g. \"Old\", \"Business\")\n\npretyp\n    The prefixed street type component. (e.g. \"US Hwy\")\n\nstreet\n    The main portion of the street name. Required.\n\nsuftyp\n    The suffixed street type component. (e.g. \"Rd\", \"Ave\")\n\nsufqual\n    The suffixed street qualifier component.\n\nsufdir\n    The suffixed street directional component.\n\nunittyp\n    The unit type, if any. (e.g. \"Fl\", \"Apt\", \"Ste\")\n\nunit\n    The unit identifer, if any.\n\ncity\n    The name of the city or locale.\n\nstate\n    The two letter postal state code.\n\nzip\n    The zero padded, five digit ZIP postal code.\n\nplus4\n    The zero padded, four digit ZIP+4 postal extension.\n\nParsing Strategy\n----------------\n\nEach component will have a regular expression, and a maximum\ncount. Components are ordered from first to last.\n\nThose components drawn from finite lists - directionals, qualifiers,\ntypes, and states - will have regular expressions composed of the union of\nthe corresponding list.\n\nA *parse* will consist of a component state, a penalty count, a list of\ncomponent strings and a counter for each component.\n\n1. Initialize an input stack, consisting of a single blank parse.\n\n#. Split the address string on whitespace into tokens.\n\n#. For each token:\n\n   A. For each component:\n\n      i. Test the token against the regular expression.\n      #. If the regexp matches, add the component name to a list of matching\n         components.\n\n   #. Initialize an empty output stack.\n\n   #. For each parse in the input stack:\n\n      i. Copy the current parse, increment the penalty count on the new parse,\n         and add it to the output stack.\n      #. For each matching component for the current token:\n\n         a. If the component state for this parse is later than the\n            matching component, continue to the next matching component.\n         #. If the component count for this parse state is equal to the \n            maximum count for the component, continue to the next matching\n            component.\n         #. Otherwise, copy the parse state, and append the token to the\n            component string, with a leading space, if necessary.\n         #. Increment the matching component counter for the current parse.\n         #. Set the component state of the current parse to the matching\n            component.\n         #. Push the new parse on to the output stack.\n\n   #. Replace the input stack with the output stack.\n\n#. Post-process number prefix/suffixes and ZIP+4 extensions.\n\n#. Score each parse by the number of components with non-empty strings,\n   minus the penalty count of the parse.\n\n#. Return the sorted list of parsed string lists.\n\n"
  },
  {
    "path": "doc/voidspace.css",
    "content": "/*\n:Authors: Ian Bicking, Michael Foord\n:Contact: fuzzyman@voidspace.org.uk\n:Date: 2005/08/26 \n:Version: 0.1.0\n:Copyright: This stylesheet has been placed in the public domain.\n:Modified By: Schuyler Erle, for geocoder.us, 2008-03-14\n\nStylesheet for Docutils.\nBased on ``blue_box.css`` by Ian Bicking\nand ``html4css1.css`` revision 1.46.\n*/\n\n@import url(html4css1.css);\n\n/* changes made by SDE */\nbody {\n  font-family: Arial, sans-serif;\n  margin-left: 10%;\n  margin-right: 10%;\n}\n\np { text-align: justify; }\ndt { font-style: italic; }\n/* end changes */\n\nem, i {\n  /* Typically serif fonts have much nicer italics */\n  font-family: Times New Roman, Times, serif;\n}\n\na.target {\n  color: blue;\n}\n\na.target {\n  color: blue;\n}\n\na.toc-backref {\n  text-decoration: none;\n  color: black;\n}\n\na.toc-backref:hover {\n  background-color: inherit;\n}\n\na:hover {\n  background-color: #cccccc;\n}\n\ndiv.attention, div.caution, div.danger, div.error, div.hint,\ndiv.important, div.note, div.tip, div.warning {\n  background-color: #cccccc;\n  padding: 3px;\n  width: 80%;\n}\n\ndiv.admonition p.admonition-title, div.hint p.admonition-title,\ndiv.important p.admonition-title, div.note p.admonition-title,\ndiv.tip p.admonition-title  {\n  text-align: center;\n  background-color: #999999;\n  display: block;\n  margin: 0;\n}\n\ndiv.attention p.admonition-title, div.caution p.admonition-title,\ndiv.danger p.admonition-title, div.error p.admonition-title,\ndiv.warning p.admonition-title {\n  color: #cc0000;\n  font-family: sans-serif;\n  text-align: center;\n  background-color: #999999;\n  display: block;\n  margin: 0;\n}\n\nh1, h2, h3, h4, h5, h6 {\n  font-family: Helvetica, Arial, sans-serif;\n  border: thin solid black;\n  /* This makes the borders rounded on Mozilla, which pleases me */\n  -moz-border-radius: 8px;\n  padding: 4px;\n}\n\nh1 {\n  background-color: #444499;\n  color: #ffffff;\n  border: medium solid black;\n}\n\nh1 a.toc-backref, h2 a.toc-backref { \n  color: #ffffff;\n}\n\nh2 {\n  background-color: #666666;\n  color: #ffffff;\n  border: medium solid black;\n}\n\nh3, h4, h5, h6 {\n  background-color: #cccccc;\n  color: #000000;\n}\n\nh3 a.toc-backref, h4 a.toc-backref, h5 a.toc-backref, \nh6 a.toc-backref { \n  color: #000000;\n}\n\nh1.title {\n  text-align: center;\n  background-color: #444499;\n  color: #eeeeee;\n  border: thick solid black;\n  -moz-border-radius: 20px;\n}\n\ntable.footnote {\n  padding-left: 0.5ex;\n}\n\ntable.citation {\n  padding-left: 0.5ex\n}\n\npre.literal-block, pre.doctest-block {\n  border: thin black solid;\n  padding: 5px;\n}\n\n.image img { border-style : solid;\n            border-width : 2px;\n}\n\nh1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {\n  font-size: 100%;\n}\n\ncode, tt {\n  color: #000066;\n}\n\n\n"
  },
  {
    "path": "gemspec",
    "content": "Gem::Specification.new do |s|\n    s.name          = 'Geocoder-US'\n    s.version       = \"2.0.4\"\n    s.author        = \"Schuyler Erle\"\n    s.email         = 'geocoder@entropyfree.com'\n    s.description   = \"US address geocoding based on TIGER/Line.\"\n    s.summary       = \"US address geocoding based on TIGER/Line.\"\n    s.homepage      = \"http://geocoder.us/\"\n    s.files         = [\"lib/geocoder/us.rb\"] + Dir[\"lib/geocoder/us/*\"] + Dir[\"tests/*\"]\n    s.require_path  = \"lib\"\n    s.test_files    = \"test/run.rb\"\n    s.add_dependency 'sqlite3-ruby', '~>1.3.1'\n    s.has_rdoc      = true\n    s.extra_rdoc_files  =   [\"README.rdoc\"]\nend\n"
  },
  {
    "path": "lib/geocoder/us/address.rb",
    "content": "require 'geocoder/us/constants'\n\nmodule Geocoder::US\n  # Defines the matching of parsed address tokens.\n  Match = {\n    # FIXME: shouldn't have to anchor :number and :zip at start/end\n    :number   => /^(\\d+\\W|[a-z]+)?(\\d+)([a-z]?)\\b/io,\n    :street   => /(?:\\b(?:\\d+\\w*|[a-z'-]+)\\s*)+/io,\n    :city     => /(?:\\b[a-z'-]+\\s*)+/io,\n    :state    => Regexp.new(State.regexp.source + \"\\s*$\", Regexp::IGNORECASE),\n    :zip      => /(\\d{5})(?:-\\d{4})?\\s*$/o,\n    :at       => /\\s(at|@|and|&)\\s/io,\n    :po_box => /\\b[P|p]*(OST|ost)*\\.*\\s*[O|o|0]*(ffice|FFICE)*\\.*\\s*[B|b][O|o|0][X|x]\\b/\n  }\n \n  # The Address class takes a US street address or place name and\n  # constructs a list of possible structured parses of the address\n  # string.\n  class Address\n    attr_accessor :text\n    attr_accessor :prenum, :number, :sufnum\n    attr_accessor :street\n    attr_accessor :city\n    attr_accessor :state\n    attr_accessor :zip, :plus4\n   \n    # Takes an address or place name string as its sole argument.\n    def initialize(text)\n      raise ArgumentError, \"no text provided\" unless text and !text.empty?\n      if text.class == Hash\n        @text = \"\"\n        assign_text_to_address text\n      else\n        @text = clean text\n        parse\n      end\n    end\n\n    # Removes any characters that aren't strictly part of an address string.\n    def clean(value)\n      value.strip \\\n           .gsub(/[^a-z0-9 ,'&@\\/-]+/io, \"\") \\\n           .gsub(/\\s+/o, \" \")\n    end\n   \n   \n    def assign_text_to_address(text)\n      if text[:address]\n        @text = clean text[:address]\n        parse\n      else\n        @street = []\n        @prenum = text[:prenum] \n        @sufnum = text[:sufnum] \n        if !text[:street].nil?\n          @street = text[:street].scan(Match[:street])\n        end\n        @number = \"\"\n        if !@street.nil?\n          if text[:number].nil?\n             @street.map! { |single_street|\n               single_street.downcase!\n               @number = single_street.scan(Match[:number])[0].to_s\n               single_street.sub! @number, \"\"\n               single_street.sub! /^\\s*,?\\s*/o, \"\"\n              }\n         else\n            @number = text[:number].to_s \n          end\n         @street = expand_streets(@street)\n          street_parts\n        end\n        @city = []\n        if !text[:city].nil?\n          @city.push(text[:city])\n        else\n          @city.push(\"\")\n        end\n        if !text[:region].nil?\n         # @state = []\n         @state = text[:region]\n          if @state.length > 2\n           # full_state = @state.strip # special case: New York\n            @state = State[@state]\n          end\n        elsif !text[:country].nil?\n          @state = text[:country]\n        elsif !text[:state].nil?\n          @state = text[:state]\n        end\n\n        @zip = text[:postal_code] \n        @plus4 = text[:plus4] \n        if !@zip\n           @zip = @plus4 = \"\"\n        end\n      end\n    end\n    \n    # Expands a token into a list of possible strings based on\n    # the Geocoder::US::Name_Abbr constant, and expands numerals and\n    # number words into their possible equivalents.\n    def expand_numbers (string)\n      if /\\b\\d+(?:st|nd|rd|th)?\\b/o.match string\n        match = $&\n        num = $&.to_i\n      elsif Ordinals.regexp.match string\n        num = Ordinals[$&]\n        match = $&\n      elsif Cardinals.regexp.match string\n        num = Cardinals[$&]\n        match = $&\n      end\n      strings = []\n      if num and num < 100\n        [num.to_s, Ordinals[num], Cardinals[num]].each {|replace|\n          strings << string.sub(match, replace)\n        }\n      else\n        strings << string\n      end\n      strings\n    end\n    \n    def parse_zip(regex_match, text)\n      idx = text.rindex(regex_match)\n      text[idx...idx+regex_match.length] = \"\"\n      text.sub! /\\s*,?\\s*$/o, \"\"\n      @zip, @plus4 = @zip.map {|s|s.strip} \n      text\n    end\n    \n    def parse_state(regex_match, text)\n      idx = text.rindex(regex_match)\n      text[idx...idx+regex_match.length] = \"\"\n      text.sub! /\\s*,?\\s*$/o, \"\"\n      @full_state = @state[0].strip # special case: New York\n      @state = State[@full_state]\n      text\n    end\n    \n    def parse_number(regex_match, text)\n      # FIXME: What if this string appears twice?\n      idx = text.index(regex_match)  \n      text[idx...idx+regex_match.length] = \"\"\n      text.sub! /^\\s*,?\\s*/o, \"\"\n      @prenum, @number, @sufnum = @number.map {|s| s and s.strip}\n      text\n    end\n    \n    def parse\n      text = @text.clone.downcase\n\n      @zip = text.scan(Match[:zip])[-1]\n      if @zip\n        text = parse_zip($&, text) \n      else\n        @zip = @plus4 = \"\"\n      end\n      \n      @state = text.scan(Match[:state])[-1]\n      if @state\n        text = parse_state($&, text)\n      else\n        @full_state = \"\"\n        @state = \"\"\n      end\n      \n      @number = text.scan(Match[:number])[0]\n      # FIXME: 230 Fish And Game Rd, Hudson NY 12534\n      if @number # and not intersection?\n        text = parse_number($&, text)\n      else\n        @prenum = @number = @sufnum = \"\"\n      end\n\n      # FIXME: special case: Name_Abbr gets a bit aggressive\n      # about replacing St with Saint. exceptional case:\n      # Sault Ste. Marie\n\n      # FIXME: PO Box should geocode to ZIP\n      @street = text.scan(Match[:street])\n      @street = expand_streets(@street)\n      # SPECIAL CASE: 1600 Pennsylvania 20050\n      @street << @full_state if @street.empty? and @state.downcase != @full_state.downcase      \n \n      @city = text.scan(Match[:city])\n      if !@city.empty?\n        @city = [@city[-1].strip]\n        add = @city.map {|item| item.gsub(Name_Abbr.regexp) {|m| Name_Abbr[m]}} \n        @city |= add\n        @city.map! {|s| s.downcase}\n        @city.uniq!\n      else\n        @city = []\n      end\n\n      # SPECIAL CASE: no city, but a state with the same name. e.g. \"New York\"\n      @city << @full_state if @state.downcase != @full_state.downcase\n    end\n    \n    def expand_streets(street)\n      if !street.empty? && !street[0].nil?\n        street.map! {|s|s.strip}\n        add = street.map {|item| item.gsub(Name_Abbr.regexp) {|m| Name_Abbr[m]}}\n        street |= add\n        add = street.map {|item| item.gsub(Std_Abbr.regexp) {|m| Std_Abbr[m]}}\n        street |= add\n        street.map! {|item| expand_numbers(item)}\n        street.flatten!\n        street.map! {|s| s.downcase}\n        street.uniq!\n      else\n        street = []\n      end\n      street\n    end\n\n    def street_parts\n      strings = []\n      # Get all the substrings delimited by whitespace\n      @street.each {|string|\n        tokens = string.split(\" \")\n        strings |= (0...tokens.length).map {|i|\n                   (i...tokens.length).map {|j| tokens[i..j].join(\" \")}}.flatten\n      }\n      strings = remove_noise_words(strings)\n\n      # Try a simpler case of adding the @number in case everything is an abbr.\n      strings += [@number] if strings.all? {|s| Std_Abbr.key? s or Name_Abbr.key? s}\n      strings.uniq\n    end\n\n    def remove_noise_words(strings)\n      # Don't return strings that consist solely of abbreviations.\n      # NOTE: Is this a micro-optimization that has edge cases that will break?\n      # Answer: Yes, it breaks on simple things like \"Prairie St\" or \"Front St\"\n      prefix = Regexp.new(\"^\" + Prefix_Type.regexp.source + \"\\s*\", Regexp::IGNORECASE)\n      suffix = Regexp.new(\"\\s*\" + Suffix_Type.regexp.source + \"$\", Regexp::IGNORECASE)\n      predxn = Regexp.new(\"^\" + Directional.regexp.source + \"\\s*\", Regexp::IGNORECASE)\n      sufdxn = Regexp.new(\"\\s*\" + Directional.regexp.source + \"$\", Regexp::IGNORECASE)\n      good_strings = strings.map {|s|\n        s = s.clone\n        s.gsub!(predxn, \"\")\n        s.gsub!(sufdxn, \"\")\n        s.gsub!(prefix, \"\")\n        s.gsub!(suffix, \"\")\n        s\n      }\n      good_strings.reject! {|s| s.empty?}\n      strings = good_strings if !good_strings.empty? {|s| not Std_Abbr.key?(s) and not Name_Abbr.key?(s)}\n      strings\n    end\n      \n    def city_parts\n      strings = []\n      @city.map {|string|\n        tokens = string.split(\" \")\n        strings |= (0...tokens.length).to_a.reverse.map {|i|\n                   (i...tokens.length).map {|j| tokens[i..j].join(\" \")}}.flatten\n      }\n      # Don't return strings that consist solely of abbreviations.\n      # NOTE: Is this a micro-optimization that has edge cases that will break?\n      # Answer: Yes, it breaks on \"Prairie\"\n      good_strings = strings.reject {|s| Std_Abbr.key? s}\n      strings = good_strings if !good_strings.empty?\n      strings.uniq\n    end\n\n    def city= (strings)\n      # NOTE: This will still fail on: 100 Broome St, 33333 (if 33333 is\n      # Broome, MT or what)\n      strings = expand_streets(strings) # fix for \"Mountain View\" -> \"Mountain Vw\"\n      match = Regexp.new('\\s*\\b(?:' + strings.join(\"|\") + ')\\b\\s*$', Regexp::IGNORECASE)\n      # only remove city from street strings if address was parsed\n      unless @text == \"\"\n        @street = @street.map {|string| string.gsub(match, '')}.select {|s|!s.empty?}\n      end\n    end\n\n    def po_box?\n      Match[:po_box].match @text\n    end\n    \n    def intersection?\n      Match[:at].match @text\n    end\n  end\nend\n"
  },
  {
    "path": "lib/geocoder/us/constants.rb",
    "content": "# coding: utf-8\nrequire 'set'\nrequire 'geocoder/us/numbers'\n\nmodule Geocoder\nend\n\nmodule Geocoder::US\n  class Map < Hash\n    # The Map class provides a two-way mapping between postal abbreviations\n    # and their fully written equivalents.\n    #attr_accessor :partial\n    attr_accessor :regexp\n    def self.[] (*items)\n      hash = super(*items)\n      #hash.build_partial\n      hash.build_match\n      hash.keys.each {|k| hash[k.downcase] = hash.fetch(k)}\n      hash.values.each {|v| hash[v.downcase] = v}\n      hash.freeze\n    end\n    # The build_partial method constructs a hash of case-insensitive,\n    # whitespace-delimited prefixes to keys and values in the two-way Map.\n    def build_partial\n      @partial = Set.new()\n      [keys, values].flatten.each {|item|\n        @partial << item.downcase\n        item.downcase.split.each {|token| @partial << token}\n      }\n    end\n    def build_match\n      @regexp = Regexp.new(\n        '\\b(' + [keys,values].flatten.join(\"|\") + ')\\b',\n        Regexp::IGNORECASE)\n    end\n    # The partial? method returns true if the key is a prefix of some\n    # key in the Map.\n    def partial? (key)\n      @partial.member? key.downcase\n    end \n    def key? (key)\n      super(key.downcase)\n    end\n    def [] (key)\n      super(key.downcase)\n    end\n  end\n\n  # The Directional constant maps compass direction words in English and\n  # Spanish to their 1- or 2- letter abbreviations.  See 2008 TIGER/Line\n  # technical documentation Appendix C for more details.\n  Directional = Map[\n    \"North\"\t=> \"N\",\n    \"South\"\t=> \"S\",\n    \"East\"\t=> \"E\",\n    \"West\"\t=> \"W\",\n    \"Northeast\"\t=> \"NE\",\n    \"Northwest\"\t=> \"NW\",\n    \"Southeast\"\t=> \"SE\",\n    \"Southwest\"\t=> \"SW\",\n    \"Norte\"\t=> \"N\",\n    \"Sur\"\t=> \"S\",\n    \"Este\"\t=> \"E\",\n    \"Oeste\"\t=> \"O\",\n    \"Noreste\"\t=> \"NE\",\n    \"Noroeste\"\t=> \"NO\",\n    \"Sudeste\"\t=> \"SE\",\n    \"Sudoeste\"\t=> \"SO\"\n  ]\n\n  # The Prefix_Qualifier constant maps feature prefix qualifiers to their\n  # abbreviations. See 2008 TIGER/Line technical documentation Appendix D.\n  Prefix_Qualifier = Map[\n    \"Alternate\"\t=> \"Alt\",\n    \"Business\"\t=> \"Bus\",\n    \"Bypass\"\t=> \"Byp\",\n    \"Extended\"\t=> \"Exd\",\n    \"Historic\"\t=> \"Hst\",\n    \"Loop\"\t=> \"Lp\",\n    \"Old\"\t=> \"Old\",\n    \"Private\"\t=> \"Pvt\",\n    \"Public\"\t=> \"Pub\",\n    \"Spur\"\t=> \"Spr\",\n  ]\n\n  # The Suffix_Qualifier constant maps feature suffix qualifiers to their\n  # abbreviations. See 2008 TIGER/Line technical documentation Appendix D.\n  Suffix_Qualifier = Map[\n    \"Access\"\t=> \"Acc\",\n    \"Alternate\"\t=> \"Alt\",\n    \"Business\"\t=> \"Bus\",\n    \"Bypass\"\t=> \"Byp\",\n    \"Connector\"\t=> \"Con\",\n    \"Extended\"\t=> \"Exd\",\n    \"Extension\"\t=> \"Exn\",\n    \"Loop\"\t=> \"Lp\",\n    \"Private\"\t=> \"Pvt\",\n    \"Public\"\t=> \"Pub\",\n    \"Scenic\"\t=> \"Scn\",\n    \"Spur\"\t=> \"Spr\",\n    \"Ramp\"\t=> \"Rmp\",\n    \"Underpass\"\t=> \"Unp\",\n    \"Overpass\"\t=> \"Ovp\",\n  ]\n\n  # The Prefix_Canonical constant maps canonical TIGER/Line street type\n  # prefixes to their abbreviations. This list is the subset of the list from\n  # 2008 TIGER/Line technical documentation Appendix E that was extracted from\n  # a TIGER/Line database import.\n  Prefix_Canonical = {\n    \"Arcade\"                            => \"Arc\",\n    \"Autopista\"                         => \"Autopista\",\n    \"Avenida\"                           => \"Ave\",\n    \"Avenue\"                            => \"Ave\",\n    \"Boulevard\"                         => \"Blvd\",\n    \"Bulevar\"                           => \"Bulevar\",\n    \"Bureau of Indian Affairs Highway\"  => \"BIA Hwy\",\n    \"Bureau of Indian Affairs Road\"     => \"BIA Rd\",\n    \"Bureau of Indian Affairs Route\"    => \"BIA Rte\",\n    \"Bureau of Land Management Road\"    => \"BLM Rd\",\n    \"Bypass\"                            => \"Byp\",\n    \"Calle\"                             => \"Cll\",\n    \"Calleja\"                           => \"Calleja\",\n    \"Callejón\"                          => \"Callejón\",\n    \"Caminito\"                          => \"Cmt\",\n    \"Camino\"                            => \"Cam\",\n    \"Carretera\"                         => \"Carr\",\n    \"Cerrada\"                           => \"Cer\",\n    \"Círculo\"                           => \"Cír\",\n    \"Commons\"                           => \"Cmns\",\n    \"Corte\"                             => \"Corte\",\n    \"County Highway\"                    => \"Co Hwy\",\n    \"County Lane\"                       => \"Co Ln\",\n    \"County Road\"                       => \"Co Rd\",\n    \"County Route\"                      => \"Co Rte\",\n    \"County State Aid Highway\"          => \"Co St Aid Hwy\",\n    \"County Trunk Highway\"              => \"Co Trunk Hwy\",\n    \"County Trunk Road\"                 => \"Co Trunk Rd\",\n    \"Court\"                             => \"Ct\",\n    \"Delta Road\"                        => \"Delta Rd\",\n    \"District of Columbia Highway\"      => \"DC Hwy\",\n    \"Driveway\"                          => \"Driveway\",\n    \"Entrada\"                           => \"Ent\",\n    \"Expreso\"                           => \"Expreso\",\n    \"Expressway\"                        => \"Expy\",\n    \"Farm Road\"                         => \"Farm Rd\",\n    \"Farm-to-Market Road\"               => \"FM\",\n    \"Fire Control Road\"                 => \"Fire Cntrl Rd\",\n    \"Fire District Road\"                => \"Fire Dist Rd\",\n    \"Fire Lane\"                         => \"Fire Ln\",\n    \"Fire Road\"                         => \"Fire Rd\",\n    \"Fire Route\"                        => \"Fire Rte\",\n    \"Fire Trail\"                        => \"Fire Trl\",\n    \"Forest Highway\"                    => \"Forest Hwy\",\n    \"Forest Road\"                       => \"Forest Rd\",\n    \"Forest Route\"                      => \"Forest Rte\",\n    \"Forest Service Road\"               => \"FS Rd\",\n    \"Highway\"                           => \"Hwy\",\n    \"Indian Route\"                      => \"Indian Rte\",\n    \"Indian Service Route\"              => \"Indian Svc Rte\",\n    \"Interstate Highway\"                => \"I-\",\n    \"Lane\"                              => \"Ln\",\n    \"Logging Road\"                      => \"Logging Rd\",\n    \"Loop\"                              => \"Loop\",\n    \"National Forest Development Road\"  => \"Nat For Dev Rd\",\n    \"Navajo Service Route\"              => \"Navajo Svc Rte\",\n    \"Parish Road\"                       => \"Parish Rd\",\n    \"Pasaje\"                            => \"Pasaje\",\n    \"Paseo\"                             => \"Pso\",\n    \"Passage\"                           => \"Psge\",\n    \"Placita\"                           => \"Pla\",\n    \"Plaza\"                             => \"Plz\",\n    \"Point\"                             => \"Pt\",\n    \"Puente\"                            => \"Puente\",\n    \"Ranch Road\"                        => \"Ranch Rd\",\n    \"Ranch to Market Road\"              => \"RM\",\n    \"Reservation Highway\"               => \"Resvn Hwy\",\n    \"Road\"                              => \"Rd\",\n    \"Route\"                             => \"Rte\",\n    \"Row\"                               => \"Row\",\n    \"Rue\"                               => \"Rue\",\n    \"Ruta\"                              => \"Ruta\",\n    \"Sector\"                            => \"Sec\",\n    \"Sendero\"                           => \"Sendero\",\n    \"Service Road\"                      => \"Svc Rd\",\n    \"Skyway\"                            => \"Skwy\",\n    \"Square\"                            => \"Sq\",\n    \"State Forest Service Road\"         => \"St FS Rd\",\n    \"State Highway\"                     => \"State Hwy\",\n    \"State Loop\"                        => \"State Loop\",\n    \"State Road\"                        => \"State Rd\",\n    \"State Route\"                       => \"State Rte\",\n    \"State Spur\"                        => \"State Spur\",\n    \"State Trunk Highway\"               => \"St Trunk Hwy\",\n    \"Terrace\"                           => \"Ter\",\n    \"Town Highway\"                      => \"Town Hwy\",\n    \"Town Road\"                         => \"Town Rd\",\n    \"Township Highway\"                  => \"Twp Hwy\",\n    \"Township Road\"                     => \"Twp Rd\",\n    \"Trail\"                             => \"Trl\",\n    \"Tribal Road\"                       => \"Tribal Rd\",\n    \"Tunnel\"                            => \"Tunl\",\n    \"US Forest Service Highway\"         => \"USFS Hwy\",\n    \"US Forest Service Road\"            => \"USFS Rd\",\n    \"US Highway\"                        => \"US Hwy\",\n    \"US Route\"                          => \"US Rte\",\n    \"Vereda\"                            => \"Ver\",\n    \"Via\"                               => \"Via\",\n    \"Vista\"                             => \"Vis\",\n  }\n\n  # The Prefix_Alternate constant maps alternate prefix street types to\n  # their canonical abbreviations. This list was merged in from the USPS\n  # list at http://www.usps.com/ncsc/lookups/abbr_suffix.txt.\n  Prefix_Alternate = {\n    \"Av\"\t\t\t=> \"Ave\",\n    \"Aven\"\t\t\t=> \"Ave\",\n    \"Avenu\"\t\t\t=> \"Ave\",\n    \"Avenue\"\t\t\t=> \"Ave\",\n    \"Avn\"\t\t\t=> \"Ave\",\n    \"Avnue\"\t\t\t=> \"Ave\",\n    \"Boul\"\t\t\t=> \"Blvd\",\n    \"Boulv\"\t\t\t=> \"Blvd\",\n    \"Bypa\"\t\t\t=> \"Byp\",\n    \"Bypas\"\t\t\t=> \"Byp\",\n    \"Byps\"\t\t\t=> \"Byp\",\n    \"Crt\"\t\t\t=> \"Ct\",\n    \"Exp\"\t\t\t=> \"Expy\",\n    \"Expr\"\t\t\t=> \"Expy\",\n    \"Express\"\t\t\t=> \"Expy\",\n    \"Expw\"\t\t\t=> \"Expy\",\n    \"Highwy\"\t\t\t=> \"Hwy\",\n    \"Hiway\"\t\t\t=> \"Hwy\",\n    \"Hiwy\"\t\t\t=> \"Hwy\",\n    \"Hway\"\t\t\t=> \"Hwy\",\n    #\"La\"\t\t\t=> \"Ln\", # causes problems with Spanglish place names\n    \"Lanes\"\t\t\t=> \"Ln\",\n    \"Loops\"\t\t\t=> \"Loop\",\n    \"Plza\"\t\t\t=> \"Plz\",\n    \"Sqr\"\t\t\t=> \"Sq\",\n    \"Sqre\"\t\t\t=> \"Sq\",\n    \"Squ\"\t\t\t=> \"Sq\",\n    \"Terr\"\t\t\t=> \"Ter\",\n    \"Tr\"\t\t\t=> \"Trl\",\n    \"Trails\"\t\t\t=> \"Trl\",\n    \"Trls\"\t\t\t=> \"Trl\",\n    \"Tunel\"\t\t\t=> \"Tunl\",\n    \"Tunls\"\t\t\t=> \"Tunl\",\n    \"Tunnels\"\t\t\t=> \"Tunl\",\n    \"Tunnl\"\t\t\t=> \"Tunl\",\n    \"Vdct\"\t\t\t=> \"Via\",\n    \"Viadct\"\t\t\t=> \"Via\",\n    \"Viaduct\"\t\t\t=> \"Via\",\n    \"Vist\"\t\t\t=> \"Vis\",\n    \"Vst\"\t\t\t=> \"Vis\",\n    \"Vsta\"\t\t\t=> \"Vis\"\n  }\n  \n  # The Prefix_Type constant merges the canonical prefix type abbreviations\n  # with their USPS accepted alternates.\n  Prefix_Type = Map[ Prefix_Canonical.merge(Prefix_Alternate) ]\n\n  # The Suffix_Canonical constant maps canonical TIGER/Line street type\n  # suffixes to their abbreviations. This list is the subset of the list from\n  # 2008 TIGER/Line technical documentation Appendix E that was extracted from\n  # a TIGER/Line database import.\n  Suffix_Canonical = {\n    \"Alley\"                             => \"Aly\",\n    \"Arcade\"                            => \"Arc\",\n    \"Avenida\"                           => \"Ave\",\n    \"Avenue\"                            => \"Ave\",\n    \"Beltway\"                           => \"Beltway\",\n    \"Boulevard\"                         => \"Blvd\",\n    \"Bridge\"                            => \"Brg\",\n    \"Bypass\"                            => \"Byp\",\n    \"Causeway\"                          => \"Cswy\",\n    \"Circle\"                            => \"Cir\",\n    \"Common\"                            => \"Cmn\",\n    \"Commons\"                           => \"Cmns\",\n    \"Corners\"                           => \"Cors\",\n    \"Court\"                             => \"Ct\",\n    \"Courts\"                            => \"Cts\",\n    \"Crescent\"                          => \"Cres\",\n    \"Crest\"                             => \"Crst\",\n    \"Crossing\"                          => \"Xing\",\n    \"Cutoff\"                            => \"Cutoff\",\n    \"Drive\"                             => \"Dr\",\n    \"Driveway\"                          => \"Driveway\",\n    \"Esplanade\"                         => \"Esplanade\",\n    \"Estates\"                           => \"Ests\",\n    \"Expressway\"                        => \"Expy\",\n    \"Forest Highway\"                    => \"Forest Hwy\",\n    \"Fork\"                              => \"Frk\",\n    \"Four-Wheel Drive Trail\"            => \"4WD Trl\",\n    \"Freeway\"                           => \"Fwy\",\n    \"Grade\"                             => \"Grade\",\n    \"Heights\"                           => \"Hts\",\n    \"Highway\"                           => \"Hwy\",\n    \"Jeep Trail\"                        => \"Jeep Trl\",\n    \"Landing\"                           => \"Lndg\",\n    \"Lane\"                              => \"Ln\",\n    \"Logging Road\"                      => \"Logging Rd\",\n    \"Loop\"                              => \"Loop\",\n    \"Motorway\"                          => \"Mtwy\",\n    \"Oval\"                              => \"Oval\",\n    \"Overpass\"                          => \"Opas\",\n    \"Parkway\"                           => \"Pkwy\",\n    \"Pass\"                              => \"Pass\",\n    \"Passage\"                           => \"Psge\",\n    \"Path\"                              => \"Path\",\n    \"Pike\"                              => \"Pike\",\n    \"Place\"                             => \"Pl\",\n    \"Plaza\"                             => \"Plz\",\n    \"Point\"                             => \"Pt\",\n    \"Pointe\"                            => \"Pointe\",\n    \"Promenade\"                         => \"Promenade\",\n    \"Railroad\"                          => \"RR\",\n    \"Railway\"                           => \"Rlwy\",\n    \"Ramp\"                              => \"Ramp\",\n    \"River\"                             => \"Riv\",\n    \"Road\"                              => \"Rd\",\n    \"Roadway\"                           => \"Roadway\",\n    \"Route\"                             => \"Rte\",\n    \"Row\"                               => \"Row\",\n    \"Rue\"                               => \"Rue\",\n    \"Service Road\"                      => \"Svc Rd\",\n    \"Skyway\"                            => \"Skwy\",\n    \"Spur\"                              => \"Spur\",\n    \"Square\"                            => \"Sq\",\n    \"Stravenue\"                         => \"Stra\",\n    \"Street\"                            => \"St\",\n    \"Strip\"                             => \"Strip\",\n    \"Terrace\"                           => \"Ter\",\n    \"Thoroughfare\"                      => \"Thoroughfare\",\n    \"Tollway\"                           => \"Tollway\",\n    \"Trace\"                             => \"Trce\",\n    \"Trafficway\"                        => \"Trfy\",\n    \"Trail\"                             => \"Trl\",\n    \"Trolley\"                           => \"Trolley\",\n    \"Truck Trail\"                       => \"Truck Trl\",\n    \"Tunnel\"                            => \"Tunl\",\n    \"Turnpike\"                          => \"Tpke\",\n    \"Viaduct\"                           => \"Viaduct\",\n    \"View\"                              => \"Vw\",\n    \"Vista\"                             => \"Vis\",\n    \"Walk\"                              => \"Walk\",\n    \"Walkway\"                           => \"Walkway\",\n    \"Way\"                               => \"Way\",\n  }\n  \n  # The Suffix_Alternate constant maps alternate suffix street types to\n  # their canonical abbreviations. This list was merged in from the USPS\n  # list at http://www.usps.com/ncsc/lookups/abbr_suffix.txt.\n  Suffix_Alternate = {\n    \"Allee\"\t\t\t=> \"Aly\",\n    \"Ally\"\t\t\t=> \"Aly\",\n    \"Av\"\t\t\t=> \"Ave\",\n    \"Aven\"\t\t\t=> \"Ave\",\n    \"Avenu\"\t\t\t=> \"Ave\",\n    \"Avenue\"\t\t\t=> \"Ave\",\n    \"Avn\"\t\t\t=> \"Ave\",\n    \"Avnue\"\t\t\t=> \"Ave\",\n    \"Boul\"\t\t\t=> \"Blvd\",\n    \"Boulv\"\t\t\t=> \"Blvd\",\n    \"Brdge\"\t\t\t=> \"Brg\",\n    \"Bypa\"\t\t\t=> \"Byp\",\n    \"Bypas\"\t\t\t=> \"Byp\",\n    \"Byps\"\t\t\t=> \"Byp\",\n    \"Causway\"\t\t\t=> \"Cswy\",\n    \"Circ\"\t\t\t=> \"Cir\",\n    \"Circl\"\t\t\t=> \"Cir\",\n    \"Crcl\"\t\t\t=> \"Cir\",\n    \"Crcle\"\t\t\t=> \"Cir\",\n    \"Crecent\"\t\t\t=> \"Cres\",\n    \"Cresent\"\t\t\t=> \"Cres\",\n    \"Crscnt\"\t\t\t=> \"Cres\",\n    \"Crsent\"\t\t\t=> \"Cres\",\n    \"Crsnt\"\t\t\t=> \"Cres\",\n    \"Crssing\"\t\t\t=> \"Xing\",\n    \"Crssng\"\t\t\t=> \"Xing\",\n    \"Crt\"\t\t\t=> \"Ct\",\n    \"Driv\"\t\t\t=> \"Dr\",\n    \"Drv\"\t\t\t=> \"Dr\",\n    \"Exp\"\t\t\t=> \"Expy\",\n    \"Expr\"\t\t\t=> \"Expy\",\n    \"Express\"\t\t\t=> \"Expy\",\n    \"Expw\"\t\t\t=> \"Expy\",\n    \"Freewy\"\t\t\t=> \"Fwy\",\n    \"Frway\"\t\t\t=> \"Fwy\",\n    \"Frwy\"\t\t\t=> \"Fwy\",\n    \"Height\"\t\t\t=> \"Hts\",\n    \"Hgts\"\t\t\t=> \"Hts\",\n    \"Highwy\"\t\t\t=> \"Hwy\",\n    \"Hiway\"\t\t\t=> \"Hwy\",\n    \"Hiwy\"\t\t\t=> \"Hwy\",\n    \"Ht\"\t\t\t=> \"Hts\",\n    \"Hway\"\t\t\t=> \"Hwy\",\n    \"La\"\t\t\t=> \"Ln\",\n    \"Lanes\"\t\t\t=> \"Ln\",\n    \"Lndng\"\t\t\t=> \"Lndg\",\n    \"Loops\"\t\t\t=> \"Loop\",\n    \"Ovl\"\t\t\t=> \"Oval\",\n    \"Parkways\"\t\t\t=> \"Pkwy\",\n    \"Parkwy\"\t\t\t=> \"Pkwy\",\n    \"Paths\"\t\t\t=> \"Path\",\n    \"Pikes\"\t\t\t=> \"Pike\",\n    \"Pkway\"\t\t\t=> \"Pkwy\",\n    \"Pkwys\"\t\t\t=> \"Pkwy\",\n    \"Pky\"\t\t\t=> \"Pkwy\",\n    \"Plza\"\t\t\t=> \"Plz\",\n    \"Rivr\"\t\t\t=> \"Riv\",\n    \"Rvr\"\t\t\t=> \"Riv\",\n    \"Spurs\"\t\t\t=> \"Spur\",\n    \"Sqr\"\t\t\t=> \"Sq\",\n    \"Sqre\"\t\t\t=> \"Sq\",\n    \"Squ\"\t\t\t=> \"Sq\",\n    \"Str\"\t\t\t=> \"St\",\n    \"Strav\"\t\t\t=> \"Stra\",\n    \"Strave\"\t\t\t=> \"Stra\",\n    \"Straven\"\t\t\t=> \"Stra\",\n    \"Stravn\"\t\t\t=> \"Stra\",\n    \"Strt\"\t\t\t=> \"St\",\n    \"Strvn\"\t\t\t=> \"Stra\",\n    \"Strvnue\"\t\t\t=> \"Stra\",\n    \"Terr\"\t\t\t=> \"Ter\",\n    \"Tpk\"\t\t\t=> \"Tpke\",\n    \"Tr\"\t\t\t=> \"Trl\",\n    \"Traces\"\t\t\t=> \"Trce\",\n    \"Trails\"\t\t\t=> \"Trl\",\n    \"Trls\"\t\t\t=> \"Trl\",\n    \"Trnpk\"\t\t\t=> \"Tpke\",\n    \"Trpk\"\t\t\t=> \"Tpke\",\n    \"Tunel\"\t\t\t=> \"Tunl\",\n    \"Tunls\"\t\t\t=> \"Tunl\",\n    \"Tunnels\"\t\t\t=> \"Tunl\",\n    \"Tunnl\"\t\t\t=> \"Tunl\",\n    \"Turnpk\"\t\t\t=> \"Tpke\",\n    \"Vist\"\t\t\t=> \"Vis\",\n    \"Vst\"\t\t\t=> \"Vis\",\n    \"Vsta\"\t\t\t=> \"Vis\",\n    \"Walks\"\t\t\t=> \"Walk\",\n    \"Wy\"\t\t\t=> \"Way\",\n  }\n\n  # The Suffix_Type constant merges the canonical suffix type abbreviations\n  # with their USPS accepted alternates.\n  Suffix_Type = Map[ Suffix_Canonical.merge(Suffix_Alternate) ]\n\n  # The Unit_Type constant lists acceptable USPS unit type abbreviations\n  # from http://www.usps.com/ncsc/lookups/abbr_sud.txt.\n  Unit_Type = Map[\n    \"Apartment\"\t=> \"Apt\",\n    \"Basement\"\t=> \"Bsmt\",\n    \"Building\"\t=> \"Bldg\",\n    \"Department\"=> \"Dept\",\n    \"Floor\"\t=> \"Fl\",\n    \"Front\"\t=> \"Frnt\",\n    \"Hangar\"\t=> \"Hngr\",\n    \"Lobby\"\t=> \"Lbby\",\n    \"Lot\"\t=> \"Lot\",\n    \"Lower\"\t=> \"Lowr\",\n    \"Office\"\t=> \"Ofc\",\n    \"Penthouse\"\t=> \"Ph\",\n    \"Pier\"\t=> \"Pier\",\n    \"Rear\"\t=> \"Rear\",\n    \"Room\"\t=> \"Rm\",\n    \"Side\"\t=> \"Side\",\n    \"Slip\"\t=> \"Slip\",\n    \"Space\"\t=> \"Spc\",\n    \"Stop\"\t=> \"Stop\",\n    \"Suite\"\t=> \"Ste\",\n    \"Trailer\"\t=> \"Trlr\",\n    \"Unit\"\t=> \"Unit\",\n    \"Upper\"\t=> \"Uppr\",\n  ]\n\n  Std_Abbr = Map[\n    [Directional, Prefix_Qualifier, Suffix_Qualifier,\n     Prefix_Type, Suffix_Type].inject({}) {|x,y|x.merge y}\n  ]\n\n  # The Name_Abbr constant maps common toponym abbreviations to their\n  # full word equivalents. This list was constructed partly by hand, and\n  # partly by matching USPS alternate abbreviations with feature names\n  # found in the TIGER/Line dataset.\n  Name_Abbr = Map[\n    \"Av\"\t=> \"Avenue\",\n    \"Ave\"\t=> \"Avenue\",\n    \"Blvd\"\t=> \"Boulevard\",\n    \"Bot\"\t=> \"Bottom\",\n    \"Boul\"\t=> \"Boulevard\",\n    \"Boulv\"\t=> \"Boulevard\",\n    \"Br\"\t=> \"Branch\",\n    \"Brg\"\t=> \"Bridge\",\n    \"Canyn\"\t=> \"Canyon\",\n    \"Cen\"\t=> \"Center\",\n    \"Cent\"\t=> \"Center\",\n    \"Cir\"\t=> \"Circle\",\n    \"Circ\"\t=> \"Circle\",\n    \"Ck\"\t=> \"Creek\",\n    \"Cnter\"\t=> \"Center\",\n    \"Cntr\"\t=> \"Center\",\n    \"Cnyn\"\t=> \"Canyon\",\n    \"Cor\"\t=> \"Corner\",\n    \"Cors\"\t=> \"Corners\",\n    \"Cp\"\t=> \"Camp\",\n    \"Cr\"\t=> \"Creek\",\n    \"Crcl\"\t=> \"Circle\",\n    \"Crcle\"\t=> \"Circle\",\n    \"Cres\"\t=> \"Crescent\",\n    \"Crscnt\"\t=> \"Crescent\",\n    \"Ct\"\t=> \"Court\",\n    \"Ctr\"\t=> \"Center\",\n    \"Cts\"\t=> \"Courts\",\n    \"Cyn\"\t=> \"Canyon\",\n    \"Div\"\t=> \"Divide\",\n    \"Dr\"\t=> \"Drive\",\n    \"Dv\"\t=> \"Divide\",\n    \"Est\"\t=> \"Estate\",\n    \"Ests\"\t=> \"Estates\",\n    \"Ext\"\t=> \"Extension\",\n    \"Extn\"\t=> \"Extension\",\n    \"Extnsn\"\t=> \"Extension\",\n    \"Forests\"\t=> \"Forest\",\n    \"Forg\"\t=> \"Forge\",\n    \"Frg\"\t=> \"Forge\",\n    \"Ft\"\t=> \"Fort\",\n    \"Gatewy\"\t=> \"Gateway\",\n    \"Gdn\"\t=> \"Garden\",\n    \"Gdns\"\t=> \"Gardens\",\n    \"Gtwy\"\t=> \"Gateway\",\n    \"Harb\"\t=> \"Harbor\",\n    \"Hbr\"\t=> \"Harbor\",\n    \"Height\"\t=> \"Heights\",\n    \"Hgts\"\t=> \"Heights\",\n    \"Highwy\"\t=> \"Highway\",\n    \"Hiway\"\t=> \"Highway\",\n    \"Hiwy\"\t=> \"Highway\",\n    \"Holws\"\t=> \"Hollow\",\n    \"Ht\"\t=> \"Heights\",\n    \"Hway\"\t=> \"Highway\",\n    \"Hwy\"\t=> \"Highway\",\n    \"Is\"\t=> \"Island\",\n    \"Iss\"\t=> \"Islands\",\n    \"Jct\"\t=> \"Junction\",\n    \"Jction\"\t=> \"Junction\",\n    \"Jctn\"\t=> \"Junction\",\n    \"Junctn\"\t=> \"Junction\",\n    \"Juncton\"\t=> \"Junction\",\n    \"Ldg\"\t=> \"Lodge\",\n    \"Lgt\"\t=> \"Light\",\n    \"Lndg\"\t=> \"Landing\",\n    \"Lodg\"\t=> \"Lodge\",\n    \"Loops\"\t=> \"Loop\",\n    \"Mt\"\t=> \"Mount\",\n    \"Mtin\"\t=> \"Mountain\",\n    \"Mtn\"\t=> \"Mountain\",\n    \"Orch\"\t=> \"Orchard\",\n    \"Parkwy\"\t=> \"Parkway\",\n    \"Pk\"\t=> \"Park\",\n    \"Pkway\"\t=> \"Parkway\",\n    \"Pkwy\"\t=> \"Parkway\",\n    \"Pky\"\t=> \"Parkway\",\n    \"Pl\"\t=> \"Place\",\n    \"Pnes\"\t=> \"Pines\",\n    \"Pr\"\t=> \"Prairie\",\n    \"Prr\"\t=> \"Prairie\",\n    \"Pt\"\t=> \"Point\",\n    \"Pts\"\t=> \"Points\",\n    \"Rdg\"\t=> \"Ridge\",\n    \"Riv\"\t=> \"River\",\n    \"Rnchs\"\t=> \"Ranch\",\n    \"Spg\"\t=> \"Spring\",\n    \"Spgs\"\t=> \"Springs\",\n    \"Spng\"\t=> \"Spring\",\n    \"Spngs\"\t=> \"Springs\",\n    \"Sq\"\t=> \"Square\",\n    \"Squ\"\t=> \"Square\",\n#    \"St\"\t=> \"Saint\",\n    \"Sta\"\t=> \"Station\",\n    \"Statn\"\t=> \"Station\",\n    \"Ste\"\t=> \"Sainte\",\n    \"Stn\"\t=> \"Station\",\n    \"Str\"\t=> \"Street\",\n    \"Ter\"\t=> \"Terrace\",\n    \"Terr\"\t=> \"Terrace\",\n    \"Tpk\"\t=> \"Turnpike\",\n    \"Tpke\"\t=> \"Turnpike\",\n    \"Tr\"\t=> \"Trail\",\n    \"Trls\"\t=> \"Trail\",\n    \"Trpk\"\t=> \"Turnpike\",\n    \"Tunls\"\t=> \"Tunnel\",\n    \"Un\"\t=> \"Union\",\n    \"Vill\"\t=> \"Village\",\n    \"Villag\"\t=> \"Village\",\n    \"Villg\"\t=> \"Village\",\n    \"Vis\"\t=> \"Vista\",\n    \"Vlg\"\t=> \"Village\",\n    \"Vlgs\"\t=> \"Villages\",\n    \"Wls\"\t=> \"Wells\",\n    \"Wy\"\t=> \"Way\",\n    \"Xing\"\t=> \"Crossing\",\n  ]\n\n  # The State constant maps US state and territory names to their 2-letter\n  # USPS abbreviations.\n  State = Map[\n    \"Alabama\"\t\t=> \"AL\",\n    \"Alaska\"\t\t=> \"AK\",\n    \"American Samoa\"\t=> \"AS\",\n    \"Arizona\"\t\t=> \"AZ\",\n    \"Arkansas\"\t\t=> \"AR\",\n    \"California\"\t=> \"CA\",\n    \"Colorado\"\t\t=> \"CO\",\n    \"Connecticut\"\t=> \"CT\",\n    \"Delaware\"\t\t=> \"DE\",\n    \"District of Columbia\" => \"DC\",\n    \"Federated States of Micronesia\" => \"FM\",\n    \"Florida\"\t\t=> \"FL\",\n    \"Georgia\"\t\t=> \"GA\",\n    \"Guam\"\t\t=> \"GU\",\n    \"Hawaii\"\t\t=> \"HI\",\n    \"Idaho\"\t\t=> \"ID\",\n    \"Illinois\"\t\t=> \"IL\",\n    \"Indiana\"\t\t=> \"IN\",\n    \"Iowa\"\t\t=> \"IA\",\n    \"Kansas\"\t\t=> \"KS\",\n    \"Kentucky\"\t\t=> \"KY\",\n    \"Louisiana\"\t\t=> \"LA\",\n    \"Maine\"\t\t=> \"ME\",\n    \"Marshall Islands\"\t=> \"MH\",\n    \"Maryland\"\t\t=> \"MD\",\n    \"Massachusetts\"\t=> \"MA\",\n    \"Michigan\"\t\t=> \"MI\",\n    \"Minnesota\"\t\t=> \"MN\",\n    \"Mississippi\"\t=> \"MS\",\n    \"Missouri\"\t\t=> \"MO\",\n    \"Montana\"\t\t=> \"MT\",\n    \"Nebraska\"\t\t=> \"NE\",\n    \"Nevada\"\t\t=> \"NV\",\n    \"New Hampshire\"\t=> \"NH\",\n    \"New Jersey\"\t=> \"NJ\",\n    \"New Mexico\"\t=> \"NM\",\n    \"New York\"\t\t=> \"NY\",\n    \"North Carolina\"\t=> \"NC\",\n    \"North Dakota\"\t=> \"ND\",\n    \"Northern Mariana Islands\"\t=> \"MP\",\n    \"Ohio\"\t\t=> \"OH\",\n    \"Oklahoma\"\t\t=> \"OK\",\n    \"Oregon\"\t\t=> \"OR\",\n    \"Palau\"\t\t=> \"PW\",\n    \"Pennsylvania\"\t=> \"PA\",\n    \"Puerto Rico\"\t=> \"PR\",\n    \"Rhode Island\"\t=> \"RI\",\n    \"South Carolina\"\t=> \"SC\",\n    \"South Dakota\"\t=> \"SD\",\n    \"Tennessee\"\t\t=> \"TN\",\n    \"Texas\"\t\t=> \"TX\",\n    \"Utah\"\t\t=> \"UT\",\n    \"Vermont\"\t\t=> \"VT\",\n    \"Virgin Islands\"\t=> \"VI\",\n    \"Virginia\"\t\t=> \"VA\",\n    \"Washington\"\t=> \"WA\",\n    \"West Virginia\"\t=> \"WV\",\n    \"Wisconsin\"\t\t=> \"WI\",\n    \"Wyoming\"\t\t=> \"WY\"\n  ]\n  \n\nend\n"
  },
  {
    "path": "lib/geocoder/us/database.rb",
    "content": "# require 'rubygems'\nrequire 'sqlite3'\n# require 'text'\n# require 'levenshtein'\n\nrequire 'set'\nrequire 'pp'\nrequire 'time'\nrequire 'thread'\n\nrequire 'geocoder/us/address'\nrequire 'geocoder/us/metaphone'\n\nmodule Geocoder\nend\n\nmodule Geocoder::US\n  # Provides an interface to a Geocoder::US database.\n  class Database\n    Street_Weight = 3.0\n    Number_Weight = 2.0\n    Parity_Weight = 1.25\n    City_Weight = 1.0\n    @@mutex = Mutex.new\n\n    # Takes the path of an SQLite 3 database prepared for Geocoder::US\n    # as the sole mandatory argument. The helper argument points to the\n    # Geocoder::US SQLite plugin; the module looks for this in the same\n    # directory as database.rb by default. The cache_size argument is\n    # measured in kilobytes and is used to set the SQLite cache size; larger\n    # values will trade memory for speed in long-running processes.\n    # dbtype option is used when your datasbase encodes it's geometry blogs according to two formats\n    # the first. default, is in a series of little-endian 4-byte ints. The second is\n    # | 1 byte Type | 4 byte SRID | 4 byte element count| 8 byte double coordinates. Use option value 2 for this\n    # second type\n    def initialize (filename, options = {})\n      defaults = {:debug => false, :cache_size => 50000,\n                  :helper => \"sqlite3.so\", :threadsafe => false,\n                  :create => false, :dbtype => 1}\n      options = defaults.merge options\n      raise ArgumentError, \"can't find database #{filename}\" \\\n        unless options[:create] or File.exists? filename\n      @db = SQLite3::Database.new( filename )\n      @st = {}\n      @dbtype = options[:dbtype]\n      @debug = options[:debug]\n      @threadsafe = options[:threadsafe]\n      tune options[:helper], options[:cache_size]\n    end\n\n    def synchronize\n      if not @threadsafe\n        @@mutex.synchronize { yield }\n      else\n        yield\n      end\n    end\n\n  #private\n\n    # Load the SQLite extension and tune the database settings.\n    # q.v. http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html\n    def tune (helper, cache_size)\n      if File.expand_path(helper) != helper\n        helper = File.join(File.dirname(__FILE__), helper)\n      end\n      synchronize do\n        # @db.create_function(\"levenshtein\", 2) do |func, word1, word2|\n        #   test1, test2 = [word1, word2].map {|w|\n        #     w.to_s.gsub(/\\W/o, \"\").downcase\n        #   }\n        #   dist = Levenshtein.distance(test1, test2)\n        #   result = dist.to_f / [test1.length, test2.length].max\n        #   func.set_result result \n        # end\n        # @db.create_function(\"rb_metaphone\", 2) do |func, string, len|\n        #  test = string.to_s.gsub(/\\W/o, \"\")\n        #  if test =~ /^(\\d+)/o\n        #    mph = $1\n        #  elsif test =~ /^([wy])$/io\n        #    mph = $1\n        #  else\n        #    mph = Text::Metaphone.metaphone test\n        #  end\n        #  func.result = mph[0...len.to_i]\n        # end\n        # @db.create_function(\"nondigit_prefix\", 1) do |func, string|\n        #   string.to_s =~ /^(.*\\D)?(\\d+)$/o\n        #   func.result = ($1 || \"\")\n        # end\n        # @db.create_function(\"digit_suffix\", 1) do |func, string|\n        #   string.to_s =~ /^(.*\\D)?(\\d+)$/o\n        #   func.result = ($2 || \"\")\n        # end\n        @db.enable_load_extension(1)\n        @db.load_extension(helper)\n        @db.enable_load_extension(0)\n        @db.cache_size = cache_size\n        @db.temp_store = \"memory\"\n        @db.synchronous = \"off\"\n      end\n    end\n\n    # Return a cached SQLite statement object, preparing it first if\n    # it's not already in the cache.\n    def prepare (sql)\n      $stderr.print \"SQL : #{sql}\\n\" if @debug\n      st = nil\n      synchronize do\n        # don't even bother cache SQL anymore, it seems to be messing things up\n        #@st[sql] = @db.prepare sql if not @st[sql] or @st[sql].closed?\n        st = @db.prepare sql\n      end\n      # return @st[sql]\n      return st\n    end\n\n    def flush_statements\n      @st = {}\n    end\n\n    # Generate enough SQL placeholders for a list of objects.\n    def placeholders_for (list)\n      ([\"?\"] * list.length).join(\",\")\n    end\n\n    # Generate enough SQL placeholders for a list of objects.\n    def metaphone_placeholders_for (list)\n      ([\"metaphone(?,5)\"] * list.length).join(\",\")\n    end\n\n    # Execute an SQL statement, bind a list of parameters, and\n    # return the result as a list of hashes.\n    def execute (sql, *params)\n      st = prepare(sql) \n      begin\n        execute_statement st, *params\n      ensure\n        st.close\n      end\n    end\n    \n    # Execute an SQLite statement object, bind the parameters,\n    # map the column names to symbols, and return the rows\n    # as a list of hashes.\n    def execute_statement (st, *params)\n      if @debug\n        start = Time.now\n        $stderr.print \"EXEC: #{params.inspect}\\n\" if !params.empty?\n      end\n      rows = []\n      synchronize do\n        result = st.execute(*params)\n        columns = result.columns.map {|c| c.to_sym}\n        result.each {|row|\n           rows << Hash[*(columns.zip(row).flatten)]}\n        \n      end\n      if @debug\n        runtime = format(\"%.3f\", Time.now - start)\n        $stderr.print \"ROWS: #{rows.length} (#{runtime}s)\\n\"\n      end\n      rows.reverse!\n    end\n   \n    def places_by_zip (city, zip)\n      execute(\"SELECT *, levenshtein(?, city) AS city_score\n               FROM place WHERE zip = ? order by priority desc;\", city, zip)\n    end\n\n    # Query the place table for by city, optional state, and zip.\n    # The metaphone index on the place table is used to match\n    # city names.\n    def places_by_city (city, tokens, state)\n      if city.nil?\n        city = \"\"\n      end\n      if state.nil? or state.empty?\n        and_state = \"\"\n        args = [city] + tokens.clone\n      else\n        and_state = \"AND state = ?\"\n        args = [city] + tokens.clone + [state]\n      end\n      metaphones = metaphone_placeholders_for tokens\n      execute(\"SELECT *, levenshtein(?, city) AS city_score\n                FROM place WHERE city_phone IN (#{metaphones}) #{and_state} order by priority desc;\", *args)\n    end\n\n    # Generate an SQL query and set of parameters against the feature and range\n    # tables for a street name and optional building number. The SQL is\n    # used by candidate_records and more_candidate_records to filter results\n    # by ZIP code.\n    def features_by_street (street, tokens)\n      metaphones = ([\"metaphone(?,5)\"] * tokens.length).join(\",\")\n      sql = \"\n        SELECT feature.*, levenshtein(?, street) AS street_score\n          FROM feature\n          WHERE street_phone IN (#{metaphones})\"\n      params = [street] + tokens\n      return [sql, params]\n    end\n\n    # Query the feature and range tables for a set of ranges, given a\n    # building number, street name, and list of candidate ZIP codes.\n    # The metaphone and ZIP code indexes on the feature table are\n    # used to match results.\n    def features_by_street_and_zip (street, tokens, zips)\n      sql, params = features_by_street(street, tokens)\n      in_list = placeholders_for zips\n      sql    += \" AND feature.zip IN (#{in_list})\"\n      params += zips\n      execute sql, *params\n    end\n\n    # Query the feature and range tables for a set of ranges, given a\n    # building number, street name, and list of candidate ZIP codes.\n    # The ZIP codes are reduced to a set of 3-digit prefixes, broadening\n    # the search area.\n    def more_features_by_street_and_zip (street, tokens, zips)\n      sql, params = features_by_street(street, tokens)\n      if !zips.empty? and !zips[0].nil?\n        #puts \"zip results 2\"\n        zip3s = zips.map {|z| z[0..2]+'%'}.to_set.to_a\n        like_list = zip3s.map {|z| \"feature.zip LIKE ?\"}.join(\" OR \")\n        sql += \" AND (#{like_list})\"\n        params += zip3s\n      end\n      execute sql, *params\n    end\n\n    def ranges_by_feature (fids, number, prenum)\n      in_list = placeholders_for fids\n      limit = 4 * fids.length\n      sql = \"\n        SELECT feature_edge.fid AS fid, range.*\n          FROM feature_edge, range\n          WHERE fid IN (#{in_list})\n          AND feature_edge.tlid = range.tlid\"\n      params = fids.clone\n      unless prenum.nil?\n        sql += \" AND prenum = ?\"\n        params += [prenum]\n      end\n      sql += \" \n          ORDER BY min(abs(fromhn - ?), abs(tohn - ?))\n          LIMIT #{limit};\"\n      params += [number, number]\n      execute sql, *params\n    end\n\n    # Query the edge table for a list of edges matching a list of edge IDs.\n    def edges (edge_ids)\n      in_list = placeholders_for edge_ids\n      sql = \"SELECT edge.* FROM edge WHERE edge.tlid IN (#{in_list})\"\n      execute sql, *edge_ids\n    end\n\n    # Query the range table for all ranges associated with the given\n    # list of edge IDs.\n    def range_ends (edge_ids)\n      in_list = placeholders_for edge_ids\n      sql = \"SELECT tlid, side,\n                    min(fromhn) > min(tohn) AS flipped,\n                    min(fromhn) AS from0, max(tohn)   AS to0,\n                    min(tohn)   AS from1, max(fromhn) AS to1\n              FROM range WHERE tlid IN (#{in_list})\n              GROUP BY tlid, side;\"\n      execute(sql, *edge_ids).map {|r|\n\tif r[:flipped].to_i == 1\n          r[:flipped] = true\n          r[:fromhn], r[:tohn] = r[:from1], r[:to1]\n        else\n          r[:flipped] = false\n          r[:fromhn], r[:tohn] = r[:from0], r[:to0]\n        end\n        [:from0, :to0, :from1, :to1].each {|k| r.delete k}\n        r\n      }\n    end\n\n    def intersections_by_fid (fids)\n      temp_db = \"temp_\" + rand(1<<32).to_s\n      temp_table = \"intersection_\" + rand(1<<32).to_s\n      execute \"ATTACH DATABASE ':memory:' as #{temp_db};\"\n      begin\n        # flush_statements # the CREATE/DROP TABLE invalidates prepared statements\n        in_list = placeholders_for fids\n        sql = \"\n          CREATE TABLE #{temp_db}.#{temp_table} AS\n            SELECT fid, substr(geometry,1,8) AS point\n                FROM feature_edge, edge \n                WHERE feature_edge.tlid = edge.tlid\n                AND fid IN (#{in_list})\n            UNION\n            SELECT fid, substr(geometry,length(geometry)-7,8) AS point\n                FROM feature_edge, edge \n                WHERE feature_edge.tlid = edge.tlid\n                AND fid IN (#{in_list});\n          CREATE INDEX #{temp_db}.#{temp_table}_pt_idx ON #{temp_table} (point);\"\n        execute sql, *(fids + fids)\n        # the a.fid < b.fid inequality guarantees consistent ordering of street\n        # names in the output\n        sql = \"\n          SELECT a.fid AS fid1, b.fid AS fid2, a.point \n              FROM #{temp_table} a, #{temp_table} b,\n                   feature f1, feature f2\n              WHERE a.point = b.point AND a.fid < b.fid\n              AND f1.fid = a.fid AND f2.fid = b.fid\n              AND f1.zip = f2.zip\n              AND f1.paflag = 'P' AND f2.paflag = 'P';\"\n        return execute sql\n      ensure\n        # flush_statements # the CREATE/DROP TABLE invalidates prepared statements\n        execute \"DETACH DATABASE #{temp_db};\"\n      end\n    end\n\n    # Query the place table for notional \"primary\" place names for each of a\n    # list of ZIP codes. Since the place table shipped with this code is\n    # bespoke, and constructed from a variety of public domain sources,\n    # the primary name for a ZIP is not always the \"right\" one.\n    def primary_places (zips)\n      in_list = placeholders_for zips\n      sql = \"SELECT * FROM place WHERE zip IN (#{in_list}) order by priority desc;\"\n      execute sql, *zips\n    end\n\n    # Given a list of rows, find the unique values for a given key.\n    def unique_values (rows, key)\n      rows.map {|r| r[key]}.to_set.to_a\n    end\n\n    # Convert a list of rows into a hash keyed by the given keys.\n    def rows_to_h (rows, *keys)\n      hash = {}\n      rows.each {|row| (hash[row.values_at(*keys)] ||= []) << row; }\n      hash\n    end\n\n    # Merge the values in the list of rows given in src into the\n    # list of rows in dest, matching rows on the given list of keys.\n    # May generate more than one row in dest for each input dest row.\n    def merge_rows! (dest, src, *keys)\n      src = rows_to_h src, *keys\n      dest.map! {|row|\n        vals = row.values_at(*keys)\n        if src.key? vals\n          src[vals].map {|row2| row.merge row2}\n        else\n          [row]\n        end\n      }\n      dest.flatten!\n    end\n\n    def find_candidates (address)\n      places = []\n      candidates = []\n\n      city = address.city.sort {|a,b|a.length <=> b.length}[0]\n      if(!address.zip.empty? && !address.zip.nil?)\n         places = places_by_zip city, address.zip \n      end\n      places = places_by_city city, address.city_parts, address.state if places.empty?\n      return [] if places.empty?\n\n      # setting city will remove city from street, so save off before\n      address.city = unique_values places, :city\n      return places if address.street.empty?\n      \n      zips = unique_values places, :zip\n      street = address.street.sort {|a,b|a.length <=> b.length}[0]\n      candidates = features_by_street_and_zip street, address.street_parts, zips\n\n      if candidates.empty?\n        candidates = more_features_by_street_and_zip street, address.street_parts, zips\n      end\n\n      merge_rows! candidates, places, :zip\n      candidates\n    end\n\n    # Given a query hash and a list of candidates, assign :number\n    # and :precision values to each candidate. If the query building\n    # number is inside the candidate range, set the number on the result\n    # and set the precision to :range; otherwise, find the closest\n    # corner and set precision to :street.\n    def assign_number! (hn, candidates)\n      hn = 0 unless hn\n      for candidate in candidates\n        fromhn, tohn = candidate[:fromhn].to_i, candidate[:tohn].to_i\n        if (hn >= fromhn and hn <= tohn) or (hn <= fromhn and hn >= tohn)\n          candidate[:number] = hn.to_s\n          candidate[:precision] = :range\n        else\n          candidate[:number] = ((hn - fromhn).abs < (hn - tohn).abs ?\n                                candidate[:fromhn] : candidate[:tohn]).to_s\n          candidate[:precision] = :street\n        end\n      end\n    end\n\n    def add_ranges! (address, candidates)\n      number = address.number.to_i\n      fids   = unique_values candidates, :fid\n      ranges = ranges_by_feature fids, number, address.prenum\n      ranges = ranges_by_feature fids, number, nil unless !ranges.empty?\n      merge_rows! candidates, ranges, :fid\n      assign_number! number, candidates\n    end\n\n    def merge_edges! (candidates)\n      edge_ids = unique_values candidates, :tlid\n      records  = edges edge_ids\n      merge_rows! candidates, records, :tlid\n      candidates.reject! {|record| record[:tlid].nil?}\n      edge_ids\n    end\n\n    def extend_ranges! (candidates)\n      edge_ids    = merge_edges! candidates\n      full_ranges = range_ends edge_ids\n      merge_rows! candidates, full_ranges, :tlid, :side\n    end\n\n    # Score a list of candidates. For each candidate:\n    # * For each item in the query:\n    # ** if the query item is blank but the candidate is not, score 0.15;\n    #    otherwise, if both are blank, score 1.0.\n    # ** If both items are set, compute the scaled Levenshtein-Damerau distance\n    #    between them, and add that value (between 0.0 and 1.0) to the score.\n    # * Add 0.5 to the score for each numbered end of the range that matches\n    #   the parity of the query number.\n    # * Add 1.0 if the query number is in the candidate range, otherwise\n    #   add a fractional value for the notional distance between the\n    #   closest candidate corner and the query.\n    # * Finally, divide the score by the total number of comparisons.\n    #   The result should be between 0.0 and 1.0, with 1.0 indicating a\n    #   perfect match.\n    def score_candidates! (address, candidates)\n      for candidate in candidates\n        candidate[:components] = {}\n        compare = [:prenum, :state, :zip]\n        denominator = compare.length + Street_Weight + City_Weight\n\n        street_score = (1.0 - candidate[:street_score].to_f) * Street_Weight\n        candidate[:components][:street] = street_score\n        city_score   = (1.0 - candidate[:city_score].to_f) * City_Weight\n        candidate[:components][:city] = city_score\n        score = street_score + city_score\n\n        compare.each {|key|\n          src  = address.send(key); src = src ? src.downcase : \"\"\n          dest = candidate[key]; dest = dest ? dest.downcase : \"\"\n          item_score = (src == dest) ? 1 : 0\n          candidate[:components][key] = item_score\n          score += item_score\n        }\n       \n        if address.number and !address.number.empty?\n          parity = subscore = 0.0\n          fromhn, tohn, assigned, hn = [\n              candidate[:fromhn], \n              candidate[:tohn], \n              candidate[:number], \n              address.number].map {|s|s.to_i}\n          if candidate[:precision] == :range\n            subscore += Number_Weight\n          elsif assigned > 0\n            # only credit number subscore if assigned\n            subscore += Number_Weight/(assigned - hn).abs.to_f\n          end\n          candidate[:components][:number] = subscore\n          if hn > 0 and assigned > 0\n            # only credit parity if a number was given *and* assigned\n            parity += Parity_Weight/2.0 if fromhn % 2 == hn % 2\n            parity += Parity_Weight/2.0 if tohn % 2 == hn % 2\n          end\n          candidate[:components][:parity] = parity\n          score += subscore + parity\n          denominator += Number_Weight + Parity_Weight\n        end\n        candidate[:components][:total] = score.to_f\n        candidate[:components][:denominator] = denominator\n        candidate[:score] = score.to_f / denominator\n      end\n    end\n\n    # Find the candidates in a list of candidates that are tied for the\n    # top score and prune the remainder from the list.\n    def best_candidates! (candidates)\n      candidates.sort! {|a,b| b[:score] <=> a[:score]}\n      #candidates.reverse_each {|c| print \"#{c[:number]} #{c[:state]} #{c[:city]} #{c[:raw_score]} #{c[:number_score]} #{c[:street_score]} #{c[:city_score]}\\n\" }\n      candidates.delete_if {|record| record[:score] < candidates[0][:score]}\n    end\n\n    # Compute the fractional interpolation distance for a query number along an\n    # edge, given all of the ranges for the same side of that edge.\n    def interpolation_distance (candidate)\n      fromhn, tohn, number = candidate.values_at(:fromhn, :tohn, :number).map{|x| x.to_i}\n      $stderr.print \"NUM : #{fromhn} < #{number} < #{tohn} (flipped? #{candidate[:flipped]})\\n\" if @debug\n      # don't need this anymore since range_ends was improved...\n      fromhn, tohn = tohn, fromhn if fromhn > tohn\n      if fromhn > number\n        0.0\n      elsif tohn < number\n        1.0\n      elsif tohn == fromhn\n        # this is not supposed to happen, per Census Bureau rules, but apparently it does anyway.\n        0.0\n      else\n        (number - fromhn) / (tohn - fromhn).to_f\n      end\n    end\n\n    # Unpack an array of little-endian 4-byte ints, and convert them into\n    # signed floats by dividing by 10^6, inverting the process used by the\n    # compress_wkb_line() function in the SQLite helper extension.\n    def unpack_geometry (geom)\n      points = []\n      if !geom.nil?       \n        if @dbtype == 2\n          # For special case?\n          #| 1 byte Type | 4 byte SRID | 4 byte element count| 8 byte double coordinates *\n          info = geom.unpack('CVVD*')\n          coords = info.slice(3, info.length)\n        else\n          #old format\n          coords = geom.unpack \"V*\" # little-endian 4-byte long ints\n          ## now map them into signed floats\n          coords.map! {|i| ( i > (1 << 31) ? i - (1 << 32) : i ) / 1_000_000.0}\n        end\n        points << [coords.shift, coords.shift] until coords.empty?\n      end\n      points\n    end\n\n    # Calculate the longitude scaling for the average of two latitudes.\n    def scale_lon (lat1,lat2)\n      # an approximation in place of lookup.rst (10e) and (10g)\n      # = scale longitude distances by the cosine of the latitude\n      # (or, actually, the mean of two latitudes)\n      # -- is this even necessary?\n      Math.cos((lat1+lat2) / 2 * Math::PI / 180)\n    end\n\n    # Simple Euclidean distances between two 2-D coordinate pairs, scaled\n    # along the longitudinal axis by scale_lon.\n    def distance (a, b)\n      dx = (b[0] - a[0]) * scale_lon(a[1], b[1])\n      dy = (b[1] - a[1]) \n      Math.sqrt(dx ** 2 + dy ** 2)\n    end\n\n    def street_side_offset (b, p1, p2)\n      # Find a point (x2, y2) that is at a distance b from a line A=(x0, y0)-(x1, y1)\n      # along a tangent B passing through (x1,y1)-(x2,y2).\n      # Let a = the length of line A\n      a = Math.sqrt((p2[0]-p1[0])**2.0 + (p2[1]-p1[1])**2.0)\n      # theta is the angle between the line A and the x axis\n      theta = Math.atan2(p2[1]-p1[1], p2[0]-p1[0])\n      # Now lines A and B form a right triangle where the third vertex is (x2, y2).\n      # Let c = the length of the hypotenuse line C=(x0,y0)-(x2,y2)\n      c = Math.sqrt(a**2.0 + b**2.0)\n      # Now alpha is the angle between lines A and C.\n      alpha = Math.atan2(b, a)\n      # Therefore the difference between theta and alpha is the angle between C and\n      # the x axis. Since we know the length of C, the lengths of the two lines\n      # parallel to the axes that form a right triangle C, and hence the\n      # coordinates (x2, y2), fall out.\n      return [p1[0] + c * Math.cos(theta - alpha), p1[1] + c * Math.sin(theta - alpha)]\n    end\n\n    # Find an interpolated point along a list of linestring vertices\n    # proportional to the given fractional distance along the line.\n    # Offset is in degrees and defaults to ~8 meters.\n    def interpolate (points, fraction, side, offset=0.000075)\n      $stderr.print \"POINTS: #{points.inspect}\" if @debug\n      return points[0] if fraction == 0.0 \n      return points[-1] if fraction == 1.0 \n      total = 0.0\n      (1...points.length).each {|n| total += distance(points[n-1], points[n])}\n      target = total * fraction\n      for n in 1...points.length\n        next if points[n-1] == points[n] # because otherwise step==0 and dx/dy==NaN\n        step = distance(points[n-1], points[n])\n        if step < target\n          target -= step\n        else\n          scale = scale_lon(points[n][1], points[n-1][1])\n          dx = (points[n][0] - points[n-1][0]) * (target/step) * scale\n          dy = (points[n][1] - points[n-1][1]) * (target/step)\n          found = [points[n-1][0]+dx, points[n-1][1]+dy]\n          return street_side_offset(offset*side, points[n-1], found)\n        end\n      end\n      # in a pathological case, points[n-1] == points[n] for n==-1\n      # so *sigh* just forget interpolating and return points[-1]\n      return points[-1]\n    end\n\n    # Find and replace the city, state, and county information\n    # in a list of candidates with the primary place information\n    # for the ZIP codes in the candidate list.\n    def canonicalize_places! (candidates)\n      zips_used  = unique_values(candidates, :zip)\n      pri_places = rows_to_h primary_places(zips_used), :zip\n      candidates.map! {|record|\n        current_places = pri_places[[record[:zip]]]\n        # FIXME: this should never happen!\n        return [] unless current_places\n        top_priority = current_places.map{|p| p[:priority]}.min\n        current_places.select {|p| p[:priority] == top_priority}.map {|p|\n          record.merge({\n            :city => p[:city], \n            :state => p[:state], \n            :fips_county => p[:fips_county]\n          })\n        }\n      } \n      candidates.flatten!\n    end\n\n    # Clean up a candidate record by formatting the score, replacing nil\n    # values with empty strings, and deleting artifacts from database\n    # queries.\n    def clean_record! (record)\n      record[:score] = format(\"%.3f\", record[:score]).to_f \\\n        unless record[:score].nil?\n      record.keys.each {|k| record[k] = \"\" if record[k].nil? } # clean up nils\n      record.delete :components unless @debug\n      record.delete_if {|k,v| k.is_a? Fixnum or\n          [:geometry, :side, :tlid, :fid, :fid1, :fid2, :street_phone,\n           :city_phone, :fromhn, :tohn, :paflag, :flipped, :street_score,\n           :city_score, :priority, :fips_class, :fips_place, :status].include? k}\n    end\n\n    def best_places (address, places, canonicalize=false)\n      return [] unless !places.empty?\n      score_candidates! address, places\n      best_candidates! places \n      canonicalize_places! places if canonicalize\n\n      # uniqify places\n      by_name = rows_to_h(places, :city, :state)\n      if !by_name.nil?\n        begin\n          by_name.values.each {|v| \n             v.sort! {|a,b|\n               a[:zip] <=> b[:zip]\n             }}\n            rescue\n\n            end\n      places = by_name.map {|k,v| v[0]}\n   \n      places.each {|record| clean_record! record}\n      places.each {|record|\n        record[:precision] = (record[:zip] == address.zip ? :zip : :city)\n      }\n      end\n      places\n    end\n\n    # Given an Address object, return a list of possible geocodes by place\n    # name. If canonicalize is true, attempt to return the \"primary\" postal\n    # place name for the given city, state, or ZIP.\n    def geocode_place (address, canonicalize=false)\n      places = []\n      places = places_by_zip address.text, address.zip if !address.zip.empty? or !address.zip.nil?\n      places = places_by_city address.text, address.city_parts, address.state if places.empty?\n      best_places address, places, canonicalize\n    end\n\n    def geocode_intersection (address, canonical_place=false)\n      candidates = find_candidates address\n      return [] if candidates.empty?\n      return best_places(address, candidates, canonical_place) if candidates[0][:street].nil?\n\n      features = rows_to_h candidates, :fid\n      intersects = intersections_by_fid features.keys.flatten\n      intersects.map! {|record|\n        feat1, feat2 = record.values_at(:fid1, :fid2).map {|k| features[[k]][0]}\n        record.merge! feat1\n        record[:street1] = record.delete(:street)\n        record[:street2] = feat2[:street]\n        record[:lon], record[:lat] = unpack_geometry(record.delete(:point))[0]\n        record[:precision] = :intersection\n        record[:street_score] = (feat1[:street_score].to_f + feat2[:street_score].to_f)/2\n        record\n      }\n      #pp(intersects)\n      \n      score_candidates! address, intersects\n      best_candidates! intersects \n\n      by_point = rows_to_h(intersects, :lon, :lat)\n      candidates = by_point.values.map {|records| records[0]}\n\n      canonicalize_places! candidates if canonical_place\n      candidates.each {|record| clean_record! record}\n      candidates\n    end\n\n    # Given an Address object, return a list of possible geocodes by address\n    # range interpolation. If canonicalize is true, attempt to return the\n    # \"primary\" street and place names, if they are different from the ones\n    # given.\n    def geocode_address (address, canonical_place=false)\n      candidates = find_candidates address\n      return [] if candidates.empty?\n      return best_places(address, candidates, canonical_place) if candidates[0][:street].nil?\n\n      score_candidates! address, candidates\n      best_candidates! candidates \n    \n      #candidates.sort {|a,b| b[:score] <=> a[:score]}.each {|candidate|\n      add_ranges! address, candidates\n      score_candidates! address, candidates\n      #pp candidates.sort {|a,b| b[:score] <=> a[:score]}\n      best_candidates! candidates \n\n      # sometimes multiple fids match the same tlid\n      by_tlid = rows_to_h candidates, :tlid\n      candidates = by_tlid.values.map {|records| records[0]}\n\n      # if no number is assigned in the query, only return one\n      # result for each street/zip combo\n      if !address.number.empty?\n        extend_ranges! candidates\n      else\n        by_street = rows_to_h candidates, :street, :zip\n        candidates = by_street.values.map {|records| records[0]}\n        merge_edges! candidates\n      end\n      candidates.map {|record|\n        dist = interpolation_distance record\n        points = unpack_geometry record[:geometry]\n        side = (record[:side] == \"R\" ? 1 : -1)\n        if record[:flipped]\n          side *= -1\n          points.reverse!\n        end\n        $stderr.print \"DIST: #{dist} FLIPPED: #{record[:flipped]} SIDE: #{side}\\n\" if @debug\n        found = interpolate points, dist, side\n        record[:lon], record[:lat] = found.map {|x| format(\"%.6f\", x).to_f}\n      }\n      \n      canonicalize_places! candidates if canonical_place\n\n      candidates.each {|record| clean_record! record}\n      candidates\n    end\n\n  public\n\n    # Geocode a given address or place name string. The max_penalty and cutoff\n    # arguments are passed to the Address parse functions. If canonicalize is\n    # true, attempt to return the \"primary\" street and place names, if they are\n    # different from the ones given.\n    #\n    # Returns possible candidate matches as a list of hashes.\n    #\n    # * The :lat and :lon values of each hash store the range-interpolated\n    #   address coordinates as latitude and longitude in the WGS84 spheroid.\n    # * The :precision value may be one of :city, :zip, :street, or :range, in\n    #   order of increasing precision.\n    # * The :score value will be a float between 0.0 and 1.0 representing\n    #   the approximate \"goodness\" of the candidate match.\n    # * The other values in the hash will represent various structured\n    #   components of the address and place name.\n    def geocode (info_to_geocode, canonical_place=false)\n      address = Address.new info_to_geocode\n      $stderr.print \"ADDR: #{address.inspect}\\n\" if @debug\n      return [] if address.city.empty? and address.zip.empty?\n      results = []\n      start_time = Time.now if @debug\n      if address.po_box? and !address.zip.empty?\n        results = geocode_place address, canonical_place\n      end\n      if address.intersection? and !address.street.empty? and address.number.empty?\n        results = geocode_intersection address, canonical_place\n      end\n      if results.empty? and !address.street.empty?\n        results = geocode_address address, canonical_place\n      end\n      if results.empty?\n        results = geocode_place address, canonical_place\n      end\n      if @debug\n        runtime = format(\"%.3f\", Time.now - start_time)\n        $stderr.print \"DONE: #{runtime}s\\n\"\n      end\n      results\n    end\n  end\nend\n"
  },
  {
    "path": "lib/geocoder/us/metaphone.rb",
    "content": "module Text # :nodoc:\nmodule Metaphone\n\n  module Rules # :nodoc:all\n    \n    # Metaphone rules.  These are simply applied in order.\n    #\n    STANDARD = [ \n      # Regexp, replacement\n      [ /([bcdfhjklmnpqrstvwxyz])\\1+/,\n                         '\\1' ],  # Remove doubled consonants except g.\n                                  # [PHP] remove c from regexp.\n      [ /^ae/,            'E' ],\n      [ /^[gkp]n/,        'N' ],\n      [ /^wr/,            'R' ],\n      [ /^x/,             'S' ],\n      [ /^wh/,            'W' ],\n      [ /mb$/,            'M' ],  # [PHP] remove $ from regexp.\n      [ /(?!^)sch/,      'SK' ],\n      [ /th/,             '0' ],\n      [ /t?ch|sh/,        'X' ],\n      [ /c(?=ia)/,        'X' ],\n      [ /[st](?=i[ao])/,  'X' ],\n      [ /s?c(?=[iey])/,   'S' ],\n      [ /[cq]/,           'K' ],\n      [ /dg(?=[iey])/,    'J' ],\n      [ /d/,              'T' ],\n      [ /g(?=h[^aeiou])/, ''  ],\n      [ /gn(ed)?/,        'N' ],\n      [ /([^g]|^)g(?=[iey])/,\n                        '\\1J' ],\n      [ /g+/,             'K' ],\n      [ /ph/,             'F' ],\n      [ /([aeiou])h(?=\\b|[^aeiou])/,\n                         '\\1' ],\n      [ /[wy](?![aeiou])/, '' ],\n      [ /z/,              'S' ],\n      [ /v/,              'F' ],\n      [ /(?!^)[aeiou]+/,  ''  ],\n    ]\n  \n    # The rules for the 'buggy' alternate implementation used by PHP etc.\n    #\n    BUGGY = STANDARD.dup\n    BUGGY[0] = [ /([bdfhjklmnpqrstvwxyz])\\1+/, '\\1' ]\n    BUGGY[6] = [ /mb/, 'M' ]\n  end\n\n  # Returns the Metaphone representation of a string. If the string contains\n  # multiple words, each word in turn is converted into its Metaphone\n  # representation. Note that only the letters A-Z are supported, so any\n  # language-specific processing should be done beforehand.\n  #\n  # If the :buggy option is set, alternate 'buggy' rules are used.\n  #\n  def metaphone(str, options={})\n    return str.strip.split(/\\s+/).map { |w| metaphone_word(w, options) }.join(' ')\n  end\n  \nprivate\n\n  def metaphone_word(w, options={})\n    # Normalise case and remove non-ASCII\n    s = w.downcase.gsub(/[^a-z]/, '')\n    # Apply the Metaphone rules\n    rules = options[:buggy] ? Rules::BUGGY : Rules::STANDARD\n    rules.each { |rx, rep| s.gsub!(rx, rep) }\n    return s.upcase\n  end\n\n  extend self\n\nend\nend\n"
  },
  {
    "path": "lib/geocoder/us/numbers.rb",
    "content": "module Geocoder\nend\n\nmodule Geocoder::US\n  # The NumberMap class provides a means for mapping ordinal\n  # and cardinal number words to digits and back.\n  class NumberMap < Hash\n    attr_accessor :regexp\n    def self.[] (array)\n      nmap = self.new({})\n      array.each {|item| nmap << item } \n      nmap.build_match\n      nmap\n    end\n    def initialize (array)\n      @count = 0\n    end\n    def build_match\n      @regexp = Regexp.new(\n        '\\b(' + keys.flatten.join(\"|\") + ')\\b',\n        Regexp::IGNORECASE)\n    end\n    def clean (key)\n      key.is_a?(String) ? key.downcase.gsub(/\\W/o, \"\") : key\n    end\n    def <<(item)\n      store clean(item), @count\n      store @count, item\n      @count += 1\n    end\n    def [] (key)\n      super(clean(key))\n    end\n  end\n\n  # The Cardinals constant maps digits to cardinal number words and back.\n  Cardinals = NumberMap[%w[\n    zero one two three four five six seven eight nine ten\n    eleven twelve thirteen fourteen fifteen sixteen seventeen\n    eighteen nineteen\n  ]]\n  Cardinal_Tens = %w[ twenty thirty forty fifty sixty seventy eighty ninety ]\n  Cardinal_Tens.each {|tens|\n    Cardinals << tens\n    (1..9).each {|n| Cardinals << tens + \"-\" + Cardinals[n]}\n  }\n\n  # The Ordinals constant maps digits to ordinal number words and back.\n  Ordinals = NumberMap[%w[\n    zeroth first second third fourth fifth sixth seventh eighth ninth\n    tenth eleventh twelfth thirteenth fourteenth fifteenth sixteenth\n    seventeenth eighteenth nineteenth\n  ]]\n  Cardinal_Tens.each {|tens|\n    Ordinals << tens.gsub(\"y\",\"ieth\")\n    (1..9).each {|n| Ordinals << tens + \"-\" + Ordinals[n]}\n  }\nend\n"
  },
  {
    "path": "lib/geocoder/us/rest.rb",
    "content": "require 'rubygems'\nrequire 'sinatra'\nrequire 'geocoder/us/database'\nrequire 'json'\n\n@@db = Geocoder::US::Database.new(ENV[\"GEOCODER_DB\"] || ARGV[0])\n\nset :port, 8081\nget '/geocode.?:format?' do\n  if params[:q]\n    results = @@db.geocode params[:q].gsub(/\\s+(and|at)\\s+/i,' ')\n    @features = []\n    results.each do |result|\n      coords = [result.delete(:lon), result.delete(:lat)]\n      result.keys.each do |key|\n        if result[key].is_a? String\n          result[key] = result[key].unpack(\"C*\").pack(\"U*\") # utf8\n        end\n      end\n      @features << {\n        :type => \"Feature\",\n        :properties => result,\n        :geometry => {\n          :type => \"Point\",\n          :coordinates => coords\n        }\n      }\n    end\n    case params[:format]\n    when /json/\n      begin\n        {\n          :type => \"FeatureCollection\",\n          :address => params[:q],\n          :features => @features\n        }.to_json\n      rescue JSON::GeneratorError\n        {\n          :type => \"FeatureCollection\",\n          :error => \"JSON::GeneratorError\",\n          :features => []\n        }.to_json\n      end\n    else\n      haml :index \n    end\n  else\n    status 400\n    \"parameter 'q' is missing\"\n  end\nend\n\nget '/health' do\n  \"All is well.\"\nend\n\ndef radius_for_precision(precision)\n  case precision\n  when /range/\n    50\n  else\n    200\n  end\nend\n\n__END__\n\n@@ layout\n%html\n  %head \n    %link(rel=\"stylesheet\" href=\"http://leaflet.cloudmade.com/dist/leaflet.css\")  \n    %script(src=\"http://leaflet.cloudmade.com/dist/leaflet.js\")\n    \n  %body\n    = yield\n\n@@ index\n%div#map(style=\"height:400px\")\n%div\n  %h2 Features\n  %table{:border => \"1\", :cellspacing => \"0\", :cellpadding => \"4\"}\n    %tr\n      - @features.first[:properties].each do |key,property|\n        %th= key\n    - @features.each do |feature|\n      %tr\n        - feature[:properties].each do |key,property|\n          %td= property\n    \n%script\n  var features = []\n  - @features.each do |feature|\n    = \"features.push(#{feature.to_json})\"\n  \n:javascript\n  var map = new L.Map('map');\n  var cloudmadeUrl = 'http://acetate.geoiq.com/tiles/acetate/{z}/{x}/{y}.png',\n      cloudmadeAttrib = 'Map data &copy; 2011 OpenStreetMap contributors, Style &copy; 2011 GeoIQ',\n      cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttrib});\n  var center = new L.LatLng(#{@features.first[:geometry][:coordinates][1]}, #{@features.first[:geometry][:coordinates][0]});\n  map.setView(center, 13).addLayer(cloudmade);\n  circleOptions = {\n      color: 'red', \n      fillColor: '#f03', \n      fillOpacity: 0.5\n  };\n  var circleLocation, circle;\n  for(var i=0; i<features.length;i++) {\n    circleOptions.fillOpacity = features[i].properties.score;\n    circleLocation = new L.LatLng(features[i].geometry.coordinates[1],features[i].geometry.coordinates[0]),\n    circle = new L.Circle(circleLocation, 200, circleOptions);\n    map.addLayer(circle);\n  }\n"
  },
  {
    "path": "lib/geocoder/us.rb",
    "content": "require \"geocoder/us/database\"\nrequire \"geocoder/us/address\"\n\n# Imports the Geocoder::US::Database and Geocoder::US::Address\n# modules.\n#\n# General usage is as follows:\n#\n#  >> require 'geocoder/us'\n#  >> db = Geocoder::US::Database.new(\"/opt/tiger/geocoder.db\")\n#  >> p db.geocode(\"1600 Pennsylvania Av, Washington DC\")\n#\n#  [{:pretyp=>\"\", :street=>\"Pennsylvania\", :sufdir=>\"NW\", :zip=>\"20502\",\n#    :lon=>-77.037528, :number=>\"1600\", :fips_county=>\"11001\", :predir=>\"\",\n#    :precision=>:range, :city=>\"Washington\", :lat=>38.898746, :suftyp=>\"Ave\",\n#    :state=>\"DC\", :prequal=>\"\", :sufqual=>\"\", :score=>0.906, :prenum=>\"\"}]\n#\n# See Geocoder::US::Database and README.txt for more details.\nmodule Geocoder::US\n  VERSION = \"2.0.0\"\nend\n"
  },
  {
    "path": "navteq/README",
    "content": "The navteq_import script in this directory is designed to be used with Navteq's\nlocal_streets layer. It works basically like tiger_import, except that you\nprovide either a list of .zip files containing the local_streets.* files on the\ncommand line, or via standard input.\n"
  },
  {
    "path": "navteq/convert.sql",
    "content": "BEGIN;\nCREATE INDEX navteq_link_id on local_streets (link_id);\n\nCREATE TEMPORARY TABLE linezip AS\n    SELECT DISTINCT tlid, zip FROM (\n        SELECT link_id AS tlid, r_postcode AS zip FROM local_streets\n           WHERE addr_type IS NOT NULL AND st_name IS NOT NULL\n           AND r_postcode IS NOT NULL\n        UNION\n        SELECT link_id AS tlid, l_postcode AS zip FROM local_streets\n           WHERE addr_type IS NOT NULL AND st_name IS NOT NULL\n           AND l_postcode IS NOT NULL\n    ) AS whatever;\n\nINSERT INTO feature\n    SELECT l.tlid, st_nm_base, metaphone(st_nm_base,5), st_nm_pref, st_typ_bef,\n           NULL, st_nm_suff, st_typ_aft, NULL, 'P', zip\n        FROM linezip l, local_streets f\n        WHERE l.tlid=f.link_id AND st_name IS NOT NULL;\n\nINSERT OR IGNORE INTO edge\n    SELECT l.tlid, compress_wkb_line(the_geom) FROM\n        (SELECT DISTINCT tlid FROM linezip) AS l, local_streets f\n        WHERE l.tlid=f.link_id AND st_name IS NOT NULL;\n\nINSERT INTO range\n    SELECT link_id, digit_suffix(l_refaddr), digit_suffix(l_nrefaddr),\n           nondigit_prefix(l_refaddr), l_postcode, 'L'\n    FROM linezip l, local_streets f\n    WHERE l.tlid=f.link_id AND l_refaddr IS NOT NULL\n    UNION\n    SELECT link_id, digit_suffix(r_refaddr), digit_suffix(r_nrefaddr),\n           nondigit_prefix(r_refaddr), r_postcode, 'R'\n    FROM linezip l, local_streets f\n    WHERE l.tlid=f.link_id AND r_refaddr IS NOT NULL;\n\nEND;\n"
  },
  {
    "path": "navteq/navteq_import",
    "content": "#!/bin/bash\n\nTMP=\"/tmp/navteq-import.$$\"\nSHPS=\"local_streets\"\nDBFS=\"\"\nBASE=$(dirname $0)\nPATH=$PATH:$BASE/../bin\nSQL=\"$BASE/../sql\"\nHELPER_LIB=\"$BASE/../lib/geocoder/us/sqlite3.so\"\nDATABASE=$1\nshift\n\nmkdir -p $TMP || exit 1\n\n[ ! -r $DATABASE ] && cat ${SQL}/create.sql ${SQL}/place.sql | sqlite3 $DATABASE\n \nif [ x\"$1\" = x\"\" ]; then\n    cat\nelse\n    ls $@\nfi | while read county; do\n    echo \"--- $county\"\n    if [ -r ${county%.zip}.zip ]; then\n        unzip -q $(ls ${county}.zip) -d $TMP\n    else\n        cp ${county%.*}.* $TMP\n    fi\n    (echo \".load $HELPER_LIB\" && \\\n     cat ${BASE}/prepare.sql && \\\n     for file in $SHPS; do\n       shp2sqlite -aS $(ls ${TMP}/${file}.shp) ${file}\n     done && \\\n     for file in $DBFS; do\n       shp2sqlite -an $(ls ${TMP}/${file}.dbf) ${file}\n     done && \\\n     cat ${BASE}/convert.sql) | sqlite3 $DATABASE\n    rm -f $TMP/*\ndone 2>&1 | tee import-$$.log\nrm -rf $TMP\n"
  },
  {
    "path": "navteq/prepare.sql",
    "content": "PRAGMA temp_store=MEMORY;\nPRAGMA journal_mode=MEMORY;\nPRAGMA synchronous=OFF;\nPRAGMA cache_size=250000;\nPRAGMA count_changes=0;\nBEGIN;\nCREATE TABLE \"local_streets\" (gid integer PRIMARY KEY,\n\"the_geom\" blob,\n\"link_id\" integer,\n\"st_name\" varchar(80),\n\"feat_id\" integer,\n\"st_langcd\" varchar(3),\n\"num_stnmes\" integer,\n\"st_nm_pref\" varchar(2),\n\"st_typ_bef\" varchar(30),\n\"st_nm_base\" varchar(35),\n\"st_nm_suff\" varchar(2),\n\"st_typ_aft\" varchar(30),\n\"st_typ_att\" varchar(1),\n\"addr_type\" varchar(1),\n\"l_refaddr\" varchar(10),\n\"l_nrefaddr\" varchar(10),\n\"l_addrsch\" varchar(1),\n\"l_addrform\" varchar(1),\n\"r_refaddr\" varchar(10),\n\"r_nrefaddr\" varchar(10),\n\"r_addrsch\" varchar(1),\n\"r_addrform\" varchar(1),\n\"ref_in_id\" integer,\n\"nref_in_id\" integer,\n\"n_shapepnt\" integer,\n\"func_class\" varchar(1),\n\"speed_cat\" varchar(1),\n\"fr_spd_lim\" integer,\n\"to_spd_lim\" integer,\n\"to_lanes\" integer,\n\"from_lanes\" integer,\n\"enh_geom\" varchar(1),\n\"lane_cat\" varchar(1),\n\"divider\" varchar(1),\n\"dir_travel\" varchar(1),\n\"l_area_id\" integer,\n\"r_area_id\" integer,\n\"l_postcode\" varchar(11),\n\"r_postcode\" varchar(11),\n\"l_numzones\" integer,\n\"r_numzones\" integer,\n\"num_ad_rng\" integer,\n\"ar_auto\" varchar(1),\n\"ar_bus\" varchar(1),\n\"ar_taxis\" varchar(1),\n\"ar_carpool\" varchar(1),\n\"ar_pedest\" varchar(1),\n\"ar_trucks\" varchar(1),\n\"ar_traff\" varchar(1),\n\"ar_deliv\" varchar(1),\n\"ar_emerveh\" varchar(1),\n\"paved\" varchar(1),\n\"private\" varchar(1),\n\"frontage\" varchar(1),\n\"bridge\" varchar(1),\n\"tunnel\" varchar(1),\n\"ramp\" varchar(1),\n\"tollway\" varchar(1),\n\"poiaccess\" varchar(1),\n\"contracc\" varchar(1),\n\"roundabout\" varchar(1),\n\"interinter\" varchar(1),\n\"undeftraff\" varchar(1),\n\"ferry_type\" varchar(1),\n\"multidigit\" varchar(1),\n\"maxattr\" varchar(1),\n\"spectrfig\" varchar(1),\n\"indescrib\" varchar(1),\n\"manoeuvre\" varchar(1),\n\"dividerleg\" varchar(1),\n\"inprocdata\" varchar(1),\n\"full_geom\" varchar(1),\n\"urban\" varchar(1),\n\"route_type\" varchar(1),\n\"dironsign\" varchar(1),\n\"explicatbl\" varchar(1),\n\"nameonrdsn\" varchar(1),\n\"postalname\" varchar(1),\n\"stalename\" varchar(1),\n\"vanityname\" varchar(1),\n\"junctionnm\" varchar(1),\n\"exitname\" varchar(1),\n\"scenic_rt\" varchar(1),\n\"scenic_nm\" varchar(1));\n--SELECT AddGeometryColumn('','local_streets','the_geom','-1','MULTILINESTRING',2);\nEND;\n"
  },
  {
    "path": "setup.rb",
    "content": "#\n# setup.rb\n#\n# Copyright (c) 2000-2005 Minero Aoki\n#\n# This program is free software.\n# You can distribute/modify this program under the terms of\n# the GNU LGPL, Lesser General Public License version 2.1.\n#\n\nunless Enumerable.method_defined?(:map)   # Ruby 1.4.6\n  module Enumerable\n    alias map collect\n  end\nend\n\nunless File.respond_to?(:read)   # Ruby 1.6\n  def File.read(fname)\n    open(fname) {|f|\n      return f.read\n    }\n  end\nend\n\nunless Errno.const_defined?(:ENOTEMPTY)   # Windows?\n  module Errno\n    class ENOTEMPTY\n      # We do not raise this exception, implementation is not needed.\n    end\n  end\nend\n\ndef File.binread(fname)\n  open(fname, 'rb') {|f|\n    return f.read\n  }\nend\n\n# for corrupted Windows' stat(2)\ndef File.dir?(path)\n  File.directory?((path[-1,1] == '/') ? path : path + '/')\nend\n\n\nclass ConfigTable\n\n  include Enumerable\n\n  def initialize(rbconfig)\n    @rbconfig = rbconfig\n    @items = []\n    @table = {}\n    # options\n    @install_prefix = nil\n    @config_opt = nil\n    @verbose = true\n    @no_harm = false\n  end\n\n  attr_accessor :install_prefix\n  attr_accessor :config_opt\n\n  attr_writer :verbose\n\n  def verbose?\n    @verbose\n  end\n\n  attr_writer :no_harm\n\n  def no_harm?\n    @no_harm\n  end\n\n  def [](key)\n    lookup(key).resolve(self)\n  end\n\n  def []=(key, val)\n    lookup(key).set val\n  end\n\n  def names\n    @items.map {|i| i.name }\n  end\n\n  def each(&block)\n    @items.each(&block)\n  end\n\n  def key?(name)\n    @table.key?(name)\n  end\n\n  def lookup(name)\n    @table[name] or setup_rb_error \"no such config item: #{name}\"\n  end\n\n  def add(item)\n    @items.push item\n    @table[item.name] = item\n  end\n\n  def remove(name)\n    item = lookup(name)\n    @items.delete_if {|i| i.name == name }\n    @table.delete_if {|name, i| i.name == name }\n    item\n  end\n\n  def load_script(path, inst = nil)\n    if File.file?(path)\n      MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path\n    end\n  end\n\n  def savefile\n    '.config'\n  end\n\n  def load_savefile\n    begin\n      File.foreach(savefile()) do |line|\n        k, v = *line.split(/=/, 2)\n        self[k] = v.strip\n      end\n    rescue Errno::ENOENT\n      setup_rb_error $!.message + \"\\n#{File.basename($0)} config first\"\n    end\n  end\n\n  def save\n    @items.each {|i| i.value }\n    File.open(savefile(), 'w') {|f|\n      @items.each do |i|\n        f.printf \"%s=%s\\n\", i.name, i.value if i.value? and i.value\n      end\n    }\n  end\n\n  def load_standard_entries\n    standard_entries(@rbconfig).each do |ent|\n      add ent\n    end\n  end\n\n  def standard_entries(rbconfig)\n    c = rbconfig\n\n    rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])\n\n    major = c['MAJOR'].to_i\n    minor = c['MINOR'].to_i\n    teeny = c['TEENY'].to_i\n    version = \"#{major}.#{minor}\"\n\n    # ruby ver. >= 1.4.4?\n    newpath_p = ((major >= 2) or\n                 ((major == 1) and\n                  ((minor >= 5) or\n                   ((minor == 4) and (teeny >= 4)))))\n\n    if c['rubylibdir']\n      # V > 1.6.3\n      libruby         = \"#{c['prefix']}/lib/ruby\"\n      librubyver      = c['rubylibdir']\n      librubyverarch  = c['archdir']\n      siteruby        = c['sitedir']\n      siterubyver     = c['sitelibdir']\n      siterubyverarch = c['sitearchdir']\n    elsif newpath_p\n      # 1.4.4 <= V <= 1.6.3\n      libruby         = \"#{c['prefix']}/lib/ruby\"\n      librubyver      = \"#{c['prefix']}/lib/ruby/#{version}\"\n      librubyverarch  = \"#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}\"\n      siteruby        = c['sitedir']\n      siterubyver     = \"$siteruby/#{version}\"\n      siterubyverarch = \"$siterubyver/#{c['arch']}\"\n    else\n      # V < 1.4.4\n      libruby         = \"#{c['prefix']}/lib/ruby\"\n      librubyver      = \"#{c['prefix']}/lib/ruby/#{version}\"\n      librubyverarch  = \"#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}\"\n      siteruby        = \"#{c['prefix']}/lib/ruby/#{version}/site_ruby\"\n      siterubyver     = siteruby\n      siterubyverarch = \"$siterubyver/#{c['arch']}\"\n    end\n    parameterize = lambda {|path|\n      path.sub(/\\A#{Regexp.quote(c['prefix'])}/, '$prefix')\n    }\n\n    if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }\n      makeprog = arg.sub(/'/, '').split(/=/, 2)[1]\n    else\n      makeprog = 'make'\n    end\n\n    [\n      ExecItem.new('installdirs', 'std/site/home',\n                   'std: install under libruby; site: install under site_ruby; home: install under $HOME')\\\n          {|val, table|\n            case val\n            when 'std'\n              table['rbdir'] = '$librubyver'\n              table['sodir'] = '$librubyverarch'\n            when 'site'\n              table['rbdir'] = '$siterubyver'\n              table['sodir'] = '$siterubyverarch'\n            when 'home'\n              setup_rb_error '$HOME was not set' unless ENV['HOME']\n              table['prefix'] = ENV['HOME']\n              table['rbdir'] = '$libdir/ruby'\n              table['sodir'] = '$libdir/ruby'\n            end\n          },\n      PathItem.new('prefix', 'path', c['prefix'],\n                   'path prefix of target environment'),\n      PathItem.new('bindir', 'path', parameterize.call(c['bindir']),\n                   'the directory for commands'),\n      PathItem.new('libdir', 'path', parameterize.call(c['libdir']),\n                   'the directory for libraries'),\n      PathItem.new('datadir', 'path', parameterize.call(c['datadir']),\n                   'the directory for shared data'),\n      PathItem.new('mandir', 'path', parameterize.call(c['mandir']),\n                   'the directory for man pages'),\n      PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),\n                   'the directory for system configuration files'),\n      PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),\n                   'the directory for local state data'),\n      PathItem.new('libruby', 'path', libruby,\n                   'the directory for ruby libraries'),\n      PathItem.new('librubyver', 'path', librubyver,\n                   'the directory for standard ruby libraries'),\n      PathItem.new('librubyverarch', 'path', librubyverarch,\n                   'the directory for standard ruby extensions'),\n      PathItem.new('siteruby', 'path', siteruby,\n          'the directory for version-independent aux ruby libraries'),\n      PathItem.new('siterubyver', 'path', siterubyver,\n                   'the directory for aux ruby libraries'),\n      PathItem.new('siterubyverarch', 'path', siterubyverarch,\n                   'the directory for aux ruby binaries'),\n      PathItem.new('rbdir', 'path', '$siterubyver',\n                   'the directory for ruby scripts'),\n      PathItem.new('sodir', 'path', '$siterubyverarch',\n                   'the directory for ruby extentions'),\n      PathItem.new('rubypath', 'path', rubypath,\n                   'the path to set to #! line'),\n      ProgramItem.new('rubyprog', 'name', rubypath,\n                      'the ruby program using for installation'),\n      ProgramItem.new('makeprog', 'name', makeprog,\n                      'the make program to compile ruby extentions'),\n      SelectItem.new('shebang', 'all/ruby/never', 'ruby',\n                     'shebang line (#!) editing mode'),\n      BoolItem.new('without-ext', 'yes/no', 'no',\n                   'does not compile/install ruby extentions')\n    ]\n  end\n  private :standard_entries\n\n  def load_multipackage_entries\n    multipackage_entries().each do |ent|\n      add ent\n    end\n  end\n\n  def multipackage_entries\n    [\n      PackageSelectionItem.new('with', 'name,name...', '', 'ALL',\n                               'package names that you want to install'),\n      PackageSelectionItem.new('without', 'name,name...', '', 'NONE',\n                               'package names that you do not want to install')\n    ]\n  end\n  private :multipackage_entries\n\n  ALIASES = {\n    'std-ruby'         => 'librubyver',\n    'stdruby'          => 'librubyver',\n    'rubylibdir'       => 'librubyver',\n    'archdir'          => 'librubyverarch',\n    'site-ruby-common' => 'siteruby',     # For backward compatibility\n    'site-ruby'        => 'siterubyver',  # For backward compatibility\n    'bin-dir'          => 'bindir',\n    'bin-dir'          => 'bindir',\n    'rb-dir'           => 'rbdir',\n    'so-dir'           => 'sodir',\n    'data-dir'         => 'datadir',\n    'ruby-path'        => 'rubypath',\n    'ruby-prog'        => 'rubyprog',\n    'ruby'             => 'rubyprog',\n    'make-prog'        => 'makeprog',\n    'make'             => 'makeprog'\n  }\n\n  def fixup\n    ALIASES.each do |ali, name|\n      @table[ali] = @table[name]\n    end\n    @items.freeze\n    @table.freeze\n    @options_re = /\\A--(#{@table.keys.join('|')})(?:=(.*))?\\z/\n  end\n\n  def parse_opt(opt)\n    m = @options_re.match(opt) or setup_rb_error \"config: unknown option #{opt}\"\n    m.to_a[1,2]\n  end\n\n  def dllext\n    @rbconfig['DLEXT']\n  end\n\n  def value_config?(name)\n    lookup(name).value?\n  end\n\n  class Item\n    def initialize(name, template, default, desc)\n      @name = name.freeze\n      @template = template\n      @value = default\n      @default = default\n      @description = desc\n    end\n\n    attr_reader :name\n    attr_reader :description\n\n    attr_accessor :default\n    alias help_default default\n\n    def help_opt\n      \"--#{@name}=#{@template}\"\n    end\n\n    def value?\n      true\n    end\n\n    def value\n      @value\n    end\n\n    def resolve(table)\n      @value.gsub(%r<\\$([^/]+)>) { table[$1] }\n    end\n\n    def set(val)\n      @value = check(val)\n    end\n\n    private\n\n    def check(val)\n      setup_rb_error \"config: --#{name} requires argument\" unless val\n      val\n    end\n  end\n\n  class BoolItem < Item\n    def config_type\n      'bool'\n    end\n\n    def help_opt\n      \"--#{@name}\"\n    end\n\n    private\n\n    def check(val)\n      return 'yes' unless val\n      case val\n      when /\\Ay(es)?\\z/i, /\\At(rue)?\\z/i then 'yes'\n      when /\\An(o)?\\z/i, /\\Af(alse)\\z/i  then 'no'\n      else\n        setup_rb_error \"config: --#{@name} accepts only yes/no for argument\"\n      end\n    end\n  end\n\n  class PathItem < Item\n    def config_type\n      'path'\n    end\n\n    private\n\n    def check(path)\n      setup_rb_error \"config: --#{@name} requires argument\"  unless path\n      path[0,1] == '$' ? path : File.expand_path(path)\n    end\n  end\n\n  class ProgramItem < Item\n    def config_type\n      'program'\n    end\n  end\n\n  class SelectItem < Item\n    def initialize(name, selection, default, desc)\n      super\n      @ok = selection.split('/')\n    end\n\n    def config_type\n      'select'\n    end\n\n    private\n\n    def check(val)\n      unless @ok.include?(val.strip)\n        setup_rb_error \"config: use --#{@name}=#{@template} (#{val})\"\n      end\n      val.strip\n    end\n  end\n\n  class ExecItem < Item\n    def initialize(name, selection, desc, &block)\n      super name, selection, nil, desc\n      @ok = selection.split('/')\n      @action = block\n    end\n\n    def config_type\n      'exec'\n    end\n\n    def value?\n      false\n    end\n\n    def resolve(table)\n      setup_rb_error \"$#{name()} wrongly used as option value\"\n    end\n\n    undef set\n\n    def evaluate(val, table)\n      v = val.strip.downcase\n      unless @ok.include?(v)\n        setup_rb_error \"invalid option --#{@name}=#{val} (use #{@template})\"\n      end\n      @action.call v, table\n    end\n  end\n\n  class PackageSelectionItem < Item\n    def initialize(name, template, default, help_default, desc)\n      super name, template, default, desc\n      @help_default = help_default\n    end\n\n    attr_reader :help_default\n\n    def config_type\n      'package'\n    end\n\n    private\n\n    def check(val)\n      unless File.dir?(\"packages/#{val}\")\n        setup_rb_error \"config: no such package: #{val}\"\n      end\n      val\n    end\n  end\n\n  class MetaConfigEnvironment\n    def initialize(config, installer)\n      @config = config\n      @installer = installer\n    end\n\n    def config_names\n      @config.names\n    end\n\n    def config?(name)\n      @config.key?(name)\n    end\n\n    def bool_config?(name)\n      @config.lookup(name).config_type == 'bool'\n    end\n\n    def path_config?(name)\n      @config.lookup(name).config_type == 'path'\n    end\n\n    def value_config?(name)\n      @config.lookup(name).config_type != 'exec'\n    end\n\n    def add_config(item)\n      @config.add item\n    end\n\n    def add_bool_config(name, default, desc)\n      @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)\n    end\n\n    def add_path_config(name, default, desc)\n      @config.add PathItem.new(name, 'path', default, desc)\n    end\n\n    def set_config_default(name, default)\n      @config.lookup(name).default = default\n    end\n\n    def remove_config(name)\n      @config.remove(name)\n    end\n\n    # For only multipackage\n    def packages\n      raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer\n      @installer.packages\n    end\n\n    # For only multipackage\n    def declare_packages(list)\n      raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer\n      @installer.packages = list\n    end\n  end\n\nend   # class ConfigTable\n\n\n# This module requires: #verbose?, #no_harm?\nmodule FileOperations\n\n  def mkdir_p(dirname, prefix = nil)\n    dirname = prefix + File.expand_path(dirname) if prefix\n    $stderr.puts \"mkdir -p #{dirname}\" if verbose?\n    return if no_harm?\n\n    # Does not check '/', it's too abnormal.\n    dirs = File.expand_path(dirname).split(%r<(?=/)>)\n    if /\\A[a-z]:\\z/i =~ dirs[0]\n      disk = dirs.shift\n      dirs[0] = disk + dirs[0]\n    end\n    dirs.each_index do |idx|\n      path = dirs[0..idx].join('')\n      Dir.mkdir path unless File.dir?(path)\n    end\n  end\n\n  def rm_f(path)\n    $stderr.puts \"rm -f #{path}\" if verbose?\n    return if no_harm?\n    force_remove_file path\n  end\n\n  def rm_rf(path)\n    $stderr.puts \"rm -rf #{path}\" if verbose?\n    return if no_harm?\n    remove_tree path\n  end\n\n  def remove_tree(path)\n    if File.symlink?(path)\n      remove_file path\n    elsif File.dir?(path)\n      remove_tree0 path\n    else\n      force_remove_file path\n    end\n  end\n\n  def remove_tree0(path)\n    Dir.foreach(path) do |ent|\n      next if ent == '.'\n      next if ent == '..'\n      entpath = \"#{path}/#{ent}\"\n      if File.symlink?(entpath)\n        remove_file entpath\n      elsif File.dir?(entpath)\n        remove_tree0 entpath\n      else\n        force_remove_file entpath\n      end\n    end\n    begin\n      Dir.rmdir path\n    rescue Errno::ENOTEMPTY\n      # directory may not be empty\n    end\n  end\n\n  def move_file(src, dest)\n    force_remove_file dest\n    begin\n      File.rename src, dest\n    rescue\n      File.open(dest, 'wb') {|f|\n        f.write File.binread(src)\n      }\n      File.chmod File.stat(src).mode, dest\n      File.unlink src\n    end\n  end\n\n  def force_remove_file(path)\n    begin\n      remove_file path\n    rescue\n    end\n  end\n\n  def remove_file(path)\n    File.chmod 0777, path\n    File.unlink path\n  end\n\n  def install(from, dest, mode, prefix = nil)\n    $stderr.puts \"install #{from} #{dest}\" if verbose?\n    return if no_harm?\n\n    realdest = prefix ? prefix + File.expand_path(dest) : dest\n    realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)\n    str = File.binread(from)\n    if diff?(str, realdest)\n      verbose_off {\n        rm_f realdest if File.exist?(realdest)\n      }\n      File.open(realdest, 'wb') {|f|\n        f.write str\n      }\n      File.chmod mode, realdest\n\n      File.open(\"#{objdir_root()}/InstalledFiles\", 'a') {|f|\n        if prefix\n          f.puts realdest.sub(prefix, '')\n        else\n          f.puts realdest\n        end\n      }\n    end\n  end\n\n  def diff?(new_content, path)\n    return true unless File.exist?(path)\n    new_content != File.binread(path)\n  end\n\n  def command(*args)\n    $stderr.puts args.join(' ') if verbose?\n    system(*args) or raise RuntimeError,\n        \"system(#{args.map{|a| a.inspect }.join(' ')}) failed\"\n  end\n\n  def ruby(*args)\n    command config('rubyprog'), *args\n  end\n  \n  def make(task = nil)\n    command(*[config('makeprog'), task].compact)\n  end\n\n  def extdir?(dir)\n    File.exist?(\"#{dir}/MANIFEST\") or File.exist?(\"#{dir}/extconf.rb\")\n  end\n\n  def files_of(dir)\n    Dir.open(dir) {|d|\n      return d.select {|ent| File.file?(\"#{dir}/#{ent}\") }\n    }\n  end\n\n  DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )\n\n  def directories_of(dir)\n    Dir.open(dir) {|d|\n      return d.select {|ent| File.dir?(\"#{dir}/#{ent}\") } - DIR_REJECT\n    }\n  end\n\nend\n\n\n# This module requires: #srcdir_root, #objdir_root, #relpath\nmodule HookScriptAPI\n\n  def get_config(key)\n    @config[key]\n  end\n\n  alias config get_config\n\n  # obsolete: use metaconfig to change configuration\n  def set_config(key, val)\n    @config[key] = val\n  end\n\n  #\n  # srcdir/objdir (works only in the package directory)\n  #\n\n  def curr_srcdir\n    \"#{srcdir_root()}/#{relpath()}\"\n  end\n\n  def curr_objdir\n    \"#{objdir_root()}/#{relpath()}\"\n  end\n\n  def srcfile(path)\n    \"#{curr_srcdir()}/#{path}\"\n  end\n\n  def srcexist?(path)\n    File.exist?(srcfile(path))\n  end\n\n  def srcdirectory?(path)\n    File.dir?(srcfile(path))\n  end\n  \n  def srcfile?(path)\n    File.file?(srcfile(path))\n  end\n\n  def srcentries(path = '.')\n    Dir.open(\"#{curr_srcdir()}/#{path}\") {|d|\n      return d.to_a - %w(. ..)\n    }\n  end\n\n  def srcfiles(path = '.')\n    srcentries(path).select {|fname|\n      File.file?(File.join(curr_srcdir(), path, fname))\n    }\n  end\n\n  def srcdirectories(path = '.')\n    srcentries(path).select {|fname|\n      File.dir?(File.join(curr_srcdir(), path, fname))\n    }\n  end\n\nend\n\n\nclass ToplevelInstaller\n\n  Version   = '3.4.1'\n  Copyright = 'Copyright (c) 2000-2005 Minero Aoki'\n\n  TASKS = [\n    [ 'all',      'do config, setup, then install' ],\n    [ 'config',   'saves your configurations' ],\n    [ 'show',     'shows current configuration' ],\n    [ 'setup',    'compiles ruby extentions and others' ],\n    [ 'install',  'installs files' ],\n    [ 'test',     'run all tests in test/' ],\n    [ 'clean',    \"does `make clean' for each extention\" ],\n    [ 'distclean',\"does `make distclean' for each extention\" ]\n  ]\n\n  def ToplevelInstaller.invoke\n    config = ConfigTable.new(load_rbconfig())\n    config.load_standard_entries\n    config.load_multipackage_entries if multipackage?\n    config.fixup\n    klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)\n    klass.new(File.dirname($0), config).invoke\n  end\n\n  def ToplevelInstaller.multipackage?\n    File.dir?(File.dirname($0) + '/packages')\n  end\n\n  def ToplevelInstaller.load_rbconfig\n    if arg = ARGV.detect {|arg| /\\A--rbconfig=/ =~ arg }\n      ARGV.delete(arg)\n      load File.expand_path(arg.split(/=/, 2)[1])\n      $\".push 'rbconfig.rb'\n    else\n      require 'rbconfig'\n    end\n    ::Config::CONFIG\n  end\n\n  def initialize(ardir_root, config)\n    @ardir = File.expand_path(ardir_root)\n    @config = config\n    # cache\n    @valid_task_re = nil\n  end\n\n  def config(key)\n    @config[key]\n  end\n\n  def inspect\n    \"#<#{self.class} #{__id__()}>\"\n  end\n\n  def invoke\n    run_metaconfigs\n    case task = parsearg_global()\n    when nil, 'all'\n      parsearg_config\n      init_installers\n      exec_config\n      exec_setup\n      exec_install\n    else\n      case task\n      when 'config', 'test'\n        ;\n      when 'clean', 'distclean'\n        @config.load_savefile if File.exist?(@config.savefile)\n      else\n        @config.load_savefile\n      end\n      __send__ \"parsearg_#{task}\"\n      init_installers\n      __send__ \"exec_#{task}\"\n    end\n  end\n  \n  def run_metaconfigs\n    @config.load_script \"#{@ardir}/metaconfig\"\n  end\n\n  def init_installers\n    @installer = Installer.new(@config, @ardir, File.expand_path('.'))\n  end\n\n  #\n  # Hook Script API bases\n  #\n\n  def srcdir_root\n    @ardir\n  end\n\n  def objdir_root\n    '.'\n  end\n\n  def relpath\n    '.'\n  end\n\n  #\n  # Option Parsing\n  #\n\n  def parsearg_global\n    while arg = ARGV.shift\n      case arg\n      when /\\A\\w+\\z/\n        setup_rb_error \"invalid task: #{arg}\" unless valid_task?(arg)\n        return arg\n      when '-q', '--quiet'\n        @config.verbose = false\n      when '--verbose'\n        @config.verbose = true\n      when '--help'\n        print_usage $stdout\n        exit 0\n      when '--version'\n        puts \"#{File.basename($0)} version #{Version}\"\n        exit 0\n      when '--copyright'\n        puts Copyright\n        exit 0\n      else\n        setup_rb_error \"unknown global option '#{arg}'\"\n      end\n    end\n    nil\n  end\n\n  def valid_task?(t)\n    valid_task_re() =~ t\n  end\n\n  def valid_task_re\n    @valid_task_re ||= /\\A(?:#{TASKS.map {|task,desc| task }.join('|')})\\z/\n  end\n\n  def parsearg_no_options\n    unless ARGV.empty?\n      task = caller(0).first.slice(%r<`parsearg_(\\w+)'>, 1)\n      setup_rb_error \"#{task}: unknown options: #{ARGV.join(' ')}\"\n    end\n  end\n\n  alias parsearg_show       parsearg_no_options\n  alias parsearg_setup      parsearg_no_options\n  alias parsearg_test       parsearg_no_options\n  alias parsearg_clean      parsearg_no_options\n  alias parsearg_distclean  parsearg_no_options\n\n  def parsearg_config\n    evalopt = []\n    set = []\n    @config.config_opt = []\n    while i = ARGV.shift\n      if /\\A--?\\z/ =~ i\n        @config.config_opt = ARGV.dup\n        break\n      end\n      name, value = *@config.parse_opt(i)\n      if @config.value_config?(name)\n        @config[name] = value\n      else\n        evalopt.push [name, value]\n      end\n      set.push name\n    end\n    evalopt.each do |name, value|\n      @config.lookup(name).evaluate value, @config\n    end\n    # Check if configuration is valid\n    set.each do |n|\n      @config[n] if @config.value_config?(n)\n    end\n  end\n\n  def parsearg_install\n    @config.no_harm = false\n    @config.install_prefix = ''\n    while a = ARGV.shift\n      case a\n      when '--no-harm'\n        @config.no_harm = true\n      when /\\A--prefix=/\n        path = a.split(/=/, 2)[1]\n        path = File.expand_path(path) unless path[0,1] == '/'\n        @config.install_prefix = path\n      else\n        setup_rb_error \"install: unknown option #{a}\"\n      end\n    end\n  end\n\n  def print_usage(out)\n    out.puts 'Typical Installation Procedure:'\n    out.puts \"  $ ruby #{File.basename $0} config\"\n    out.puts \"  $ ruby #{File.basename $0} setup\"\n    out.puts \"  # ruby #{File.basename $0} install (may require root privilege)\"\n    out.puts\n    out.puts 'Detailed Usage:'\n    out.puts \"  ruby #{File.basename $0} <global option>\"\n    out.puts \"  ruby #{File.basename $0} [<global options>] <task> [<task options>]\"\n\n    fmt = \"  %-24s %s\\n\"\n    out.puts\n    out.puts 'Global options:'\n    out.printf fmt, '-q,--quiet',   'suppress message outputs'\n    out.printf fmt, '   --verbose', 'output messages verbosely'\n    out.printf fmt, '   --help',    'print this message'\n    out.printf fmt, '   --version', 'print version and quit'\n    out.printf fmt, '   --copyright',  'print copyright and quit'\n    out.puts\n    out.puts 'Tasks:'\n    TASKS.each do |name, desc|\n      out.printf fmt, name, desc\n    end\n\n    fmt = \"  %-24s %s [%s]\\n\"\n    out.puts\n    out.puts 'Options for CONFIG or ALL:'\n    @config.each do |item|\n      out.printf fmt, item.help_opt, item.description, item.help_default\n    end\n    out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',\"running ruby's\"\n    out.puts\n    out.puts 'Options for INSTALL:'\n    out.printf fmt, '--no-harm', 'only display what to do if given', 'off'\n    out.printf fmt, '--prefix=path',  'install path prefix', ''\n    out.puts\n  end\n\n  #\n  # Task Handlers\n  #\n\n  def exec_config\n    @installer.exec_config\n    @config.save   # must be final\n  end\n\n  def exec_setup\n    @installer.exec_setup\n  end\n\n  def exec_install\n    @installer.exec_install\n  end\n\n  def exec_test\n    @installer.exec_test\n  end\n\n  def exec_show\n    @config.each do |i|\n      printf \"%-20s %s\\n\", i.name, i.value if i.value?\n    end\n  end\n\n  def exec_clean\n    @installer.exec_clean\n  end\n\n  def exec_distclean\n    @installer.exec_distclean\n  end\n\nend   # class ToplevelInstaller\n\n\nclass ToplevelInstallerMulti < ToplevelInstaller\n\n  include FileOperations\n\n  def initialize(ardir_root, config)\n    super\n    @packages = directories_of(\"#{@ardir}/packages\")\n    raise 'no package exists' if @packages.empty?\n    @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))\n  end\n\n  def run_metaconfigs\n    @config.load_script \"#{@ardir}/metaconfig\", self\n    @packages.each do |name|\n      @config.load_script \"#{@ardir}/packages/#{name}/metaconfig\"\n    end\n  end\n\n  attr_reader :packages\n\n  def packages=(list)\n    raise 'package list is empty' if list.empty?\n    list.each do |name|\n      raise \"directory packages/#{name} does not exist\"\\\n              unless File.dir?(\"#{@ardir}/packages/#{name}\")\n    end\n    @packages = list\n  end\n\n  def init_installers\n    @installers = {}\n    @packages.each do |pack|\n      @installers[pack] = Installer.new(@config,\n                                       \"#{@ardir}/packages/#{pack}\",\n                                       \"packages/#{pack}\")\n    end\n    with    = extract_selection(config('with'))\n    without = extract_selection(config('without'))\n    @selected = @installers.keys.select {|name|\n                  (with.empty? or with.include?(name)) \\\n                      and not without.include?(name)\n                }\n  end\n\n  def extract_selection(list)\n    a = list.split(/,/)\n    a.each do |name|\n      setup_rb_error \"no such package: #{name}\"  unless @installers.key?(name)\n    end\n    a\n  end\n\n  def print_usage(f)\n    super\n    f.puts 'Inluded packages:'\n    f.puts '  ' + @packages.sort.join(' ')\n    f.puts\n  end\n\n  #\n  # Task Handlers\n  #\n\n  def exec_config\n    run_hook 'pre-config'\n    each_selected_installers {|inst| inst.exec_config }\n    run_hook 'post-config'\n    @config.save   # must be final\n  end\n\n  def exec_setup\n    run_hook 'pre-setup'\n    each_selected_installers {|inst| inst.exec_setup }\n    run_hook 'post-setup'\n  end\n\n  def exec_install\n    run_hook 'pre-install'\n    each_selected_installers {|inst| inst.exec_install }\n    run_hook 'post-install'\n  end\n\n  def exec_test\n    run_hook 'pre-test'\n    each_selected_installers {|inst| inst.exec_test }\n    run_hook 'post-test'\n  end\n\n  def exec_clean\n    rm_f @config.savefile\n    run_hook 'pre-clean'\n    each_selected_installers {|inst| inst.exec_clean }\n    run_hook 'post-clean'\n  end\n\n  def exec_distclean\n    rm_f @config.savefile\n    run_hook 'pre-distclean'\n    each_selected_installers {|inst| inst.exec_distclean }\n    run_hook 'post-distclean'\n  end\n\n  #\n  # lib\n  #\n\n  def each_selected_installers\n    Dir.mkdir 'packages' unless File.dir?('packages')\n    @selected.each do |pack|\n      $stderr.puts \"Processing the package `#{pack}' ...\" if verbose?\n      Dir.mkdir \"packages/#{pack}\" unless File.dir?(\"packages/#{pack}\")\n      Dir.chdir \"packages/#{pack}\"\n      yield @installers[pack]\n      Dir.chdir '../..'\n    end\n  end\n\n  def run_hook(id)\n    @root_installer.run_hook id\n  end\n\n  # module FileOperations requires this\n  def verbose?\n    @config.verbose?\n  end\n\n  # module FileOperations requires this\n  def no_harm?\n    @config.no_harm?\n  end\n\nend   # class ToplevelInstallerMulti\n\n\nclass Installer\n\n  FILETYPES = %w( bin lib ext data conf man )\n\n  include FileOperations\n  include HookScriptAPI\n\n  def initialize(config, srcroot, objroot)\n    @config = config\n    @srcdir = File.expand_path(srcroot)\n    @objdir = File.expand_path(objroot)\n    @currdir = '.'\n  end\n\n  def inspect\n    \"#<#{self.class} #{File.basename(@srcdir)}>\"\n  end\n\n  def noop(rel)\n  end\n\n  #\n  # Hook Script API base methods\n  #\n\n  def srcdir_root\n    @srcdir\n  end\n\n  def objdir_root\n    @objdir\n  end\n\n  def relpath\n    @currdir\n  end\n\n  #\n  # Config Access\n  #\n\n  # module FileOperations requires this\n  def verbose?\n    @config.verbose?\n  end\n\n  # module FileOperations requires this\n  def no_harm?\n    @config.no_harm?\n  end\n\n  def verbose_off\n    begin\n      save, @config.verbose = @config.verbose?, false\n      yield\n    ensure\n      @config.verbose = save\n    end\n  end\n\n  #\n  # TASK config\n  #\n\n  def exec_config\n    exec_task_traverse 'config'\n  end\n\n  alias config_dir_bin noop\n  alias config_dir_lib noop\n\n  def config_dir_ext(rel)\n    extconf if extdir?(curr_srcdir())\n  end\n\n  alias config_dir_data noop\n  alias config_dir_conf noop\n  alias config_dir_man noop\n\n  def extconf\n    ruby \"#{curr_srcdir()}/extconf.rb\", *@config.config_opt\n  end\n\n  #\n  # TASK setup\n  #\n\n  def exec_setup\n    exec_task_traverse 'setup'\n  end\n\n  def setup_dir_bin(rel)\n    files_of(curr_srcdir()).each do |fname|\n      update_shebang_line \"#{curr_srcdir()}/#{fname}\"\n    end\n  end\n\n  alias setup_dir_lib noop\n\n  def setup_dir_ext(rel)\n    make if extdir?(curr_srcdir())\n  end\n\n  alias setup_dir_data noop\n  alias setup_dir_conf noop\n  alias setup_dir_man noop\n\n  def update_shebang_line(path)\n    return if no_harm?\n    return if config('shebang') == 'never'\n    old = Shebang.load(path)\n    if old\n      $stderr.puts \"warning: #{path}: Shebang line includes too many args.  It is not portable and your program may not work.\" if old.args.size > 1\n      new = new_shebang(old)\n      return if new.to_s == old.to_s\n    else\n      return unless config('shebang') == 'all'\n      new = Shebang.new(config('rubypath'))\n    end\n    $stderr.puts \"updating shebang: #{File.basename(path)}\" if verbose?\n    open_atomic_writer(path) {|output|\n      File.open(path, 'rb') {|f|\n        f.gets if old   # discard\n        output.puts new.to_s\n        output.print f.read\n      }\n    }\n  end\n\n  def new_shebang(old)\n    if /\\Aruby/ =~ File.basename(old.cmd)\n      Shebang.new(config('rubypath'), old.args)\n    elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'\n      Shebang.new(config('rubypath'), old.args[1..-1])\n    else\n      return old unless config('shebang') == 'all'\n      Shebang.new(config('rubypath'))\n    end\n  end\n\n  def open_atomic_writer(path, &block)\n    tmpfile = File.basename(path) + '.tmp'\n    begin\n      File.open(tmpfile, 'wb', &block)\n      File.rename tmpfile, File.basename(path)\n    ensure\n      File.unlink tmpfile if File.exist?(tmpfile)\n    end\n  end\n\n  class Shebang\n    def Shebang.load(path)\n      line = nil\n      File.open(path) {|f|\n        line = f.gets\n      }\n      return nil unless /\\A#!/ =~ line\n      parse(line)\n    end\n\n    def Shebang.parse(line)\n      cmd, *args = *line.strip.sub(/\\A\\#!/, '').split(' ')\n      new(cmd, args)\n    end\n\n    def initialize(cmd, args = [])\n      @cmd = cmd\n      @args = args\n    end\n\n    attr_reader :cmd\n    attr_reader :args\n\n    def to_s\n      \"#! #{@cmd}\" + (@args.empty? ? '' : \" #{@args.join(' ')}\")\n    end\n  end\n\n  #\n  # TASK install\n  #\n\n  def exec_install\n    rm_f 'InstalledFiles'\n    exec_task_traverse 'install'\n  end\n\n  def install_dir_bin(rel)\n    install_files targetfiles(), \"#{config('bindir')}/#{rel}\", 0755\n  end\n\n  def install_dir_lib(rel)\n    install_files libfiles(), \"#{config('rbdir')}/#{rel}\", 0644\n  end\n\n  def install_dir_ext(rel)\n    return unless extdir?(curr_srcdir())\n    install_files rubyextentions('.'),\n                  \"#{config('sodir')}/#{File.dirname(rel)}\",\n                  0555\n  end\n\n  def install_dir_data(rel)\n    install_files targetfiles(), \"#{config('datadir')}/#{rel}\", 0644\n  end\n\n  def install_dir_conf(rel)\n    # FIXME: should not remove current config files\n    # (rename previous file to .old/.org)\n    install_files targetfiles(), \"#{config('sysconfdir')}/#{rel}\", 0644\n  end\n\n  def install_dir_man(rel)\n    install_files targetfiles(), \"#{config('mandir')}/#{rel}\", 0644\n  end\n\n  def install_files(list, dest, mode)\n    mkdir_p dest, @config.install_prefix\n    list.each do |fname|\n      install fname, dest, mode, @config.install_prefix\n    end\n  end\n\n  def libfiles\n    glob_reject(%w(*.y *.output), targetfiles())\n  end\n\n  def rubyextentions(dir)\n    ents = glob_select(\"*.#{@config.dllext}\", targetfiles())\n    if ents.empty?\n      setup_rb_error \"no ruby extention exists: 'ruby #{$0} setup' first\"\n    end\n    ents\n  end\n\n  def targetfiles\n    mapdir(existfiles() - hookfiles())\n  end\n\n  def mapdir(ents)\n    ents.map {|ent|\n      if File.exist?(ent)\n      then ent                         # objdir\n      else \"#{curr_srcdir()}/#{ent}\"   # srcdir\n      end\n    }\n  end\n\n  # picked up many entries from cvs-1.11.1/src/ignore.c\n  JUNK_FILES = %w( \n    core RCSLOG tags TAGS .make.state\n    .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb\n    *~ *.old *.bak *.BAK *.orig *.rej _$* *$\n\n    *.org *.in .*\n  )\n\n  def existfiles\n    glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))\n  end\n\n  def hookfiles\n    %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|\n      %w( config setup install clean ).map {|t| sprintf(fmt, t) }\n    }.flatten\n  end\n\n  def glob_select(pat, ents)\n    re = globs2re([pat])\n    ents.select {|ent| re =~ ent }\n  end\n\n  def glob_reject(pats, ents)\n    re = globs2re(pats)\n    ents.reject {|ent| re =~ ent }\n  end\n\n  GLOB2REGEX = {\n    '.' => '\\.',\n    '$' => '\\$',\n    '#' => '\\#',\n    '*' => '.*'\n  }\n\n  def globs2re(pats)\n    /\\A(?:#{\n      pats.map {|pat| pat.gsub(/[\\.\\$\\#\\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')\n    })\\z/\n  end\n\n  #\n  # TASK test\n  #\n\n  TESTDIR = 'test'\n\n  def exec_test\n    unless File.directory?('test')\n      $stderr.puts 'no test in this package' if verbose?\n      return\n    end\n    $stderr.puts 'Running tests...' if verbose?\n    begin\n      require 'test/unit'\n    rescue LoadError\n      setup_rb_error 'test/unit cannot loaded.  You need Ruby 1.8 or later to invoke this task.'\n    end\n    runner = Test::Unit::AutoRunner.new(true)\n    runner.to_run << TESTDIR\n    runner.run\n  end\n\n  #\n  # TASK clean\n  #\n\n  def exec_clean\n    exec_task_traverse 'clean'\n    rm_f @config.savefile\n    rm_f 'InstalledFiles'\n  end\n\n  alias clean_dir_bin noop\n  alias clean_dir_lib noop\n  alias clean_dir_data noop\n  alias clean_dir_conf noop\n  alias clean_dir_man noop\n\n  def clean_dir_ext(rel)\n    return unless extdir?(curr_srcdir())\n    make 'clean' if File.file?('Makefile')\n  end\n\n  #\n  # TASK distclean\n  #\n\n  def exec_distclean\n    exec_task_traverse 'distclean'\n    rm_f @config.savefile\n    rm_f 'InstalledFiles'\n  end\n\n  alias distclean_dir_bin noop\n  alias distclean_dir_lib noop\n\n  def distclean_dir_ext(rel)\n    return unless extdir?(curr_srcdir())\n    make 'distclean' if File.file?('Makefile')\n  end\n\n  alias distclean_dir_data noop\n  alias distclean_dir_conf noop\n  alias distclean_dir_man noop\n\n  #\n  # Traversing\n  #\n\n  def exec_task_traverse(task)\n    run_hook \"pre-#{task}\"\n    FILETYPES.each do |type|\n      if type == 'ext' and config('without-ext') == 'yes'\n        $stderr.puts 'skipping ext/* by user option' if verbose?\n        next\n      end\n      traverse task, type, \"#{task}_dir_#{type}\"\n    end\n    run_hook \"post-#{task}\"\n  end\n\n  def traverse(task, rel, mid)\n    dive_into(rel) {\n      run_hook \"pre-#{task}\"\n      __send__ mid, rel.sub(%r[\\A.*?(?:/|\\z)], '')\n      directories_of(curr_srcdir()).each do |d|\n        traverse task, \"#{rel}/#{d}\", mid\n      end\n      run_hook \"post-#{task}\"\n    }\n  end\n\n  def dive_into(rel)\n    return unless File.dir?(\"#{@srcdir}/#{rel}\")\n\n    dir = File.basename(rel)\n    Dir.mkdir dir unless File.dir?(dir)\n    prevdir = Dir.pwd\n    Dir.chdir dir\n    $stderr.puts '---> ' + rel if verbose?\n    @currdir = rel\n    yield\n    Dir.chdir prevdir\n    $stderr.puts '<--- ' + rel if verbose?\n    @currdir = File.dirname(rel)\n  end\n\n  def run_hook(id)\n    path = [ \"#{curr_srcdir()}/#{id}\",\n             \"#{curr_srcdir()}/#{id}.rb\" ].detect {|cand| File.file?(cand) }\n    return unless path\n    begin\n      instance_eval File.read(path), path, 1\n    rescue\n      raise if $DEBUG\n      setup_rb_error \"hook #{path} failed:\\n\" + $!.message\n    end\n  end\n\nend   # class Installer\n\n\nclass SetupError < StandardError; end\n\ndef setup_rb_error(msg)\n  raise SetupError, msg\nend\n\nif $0 == __FILE__\n  begin\n    ToplevelInstaller.invoke\n  rescue SetupError\n    raise if $DEBUG\n    $stderr.puts $!.message\n    $stderr.puts \"Try 'ruby #{$0} --help' for detailed usage.\"\n    exit 1\n  end\nend\n"
  },
  {
    "path": "src/Makefile",
    "content": "all:\n\t$(MAKE) -C libsqlite3_geocoder\n\t$(MAKE)\t-C liblwgeom\n\t$(MAKE) -C shp2sqlite\n\nclean:\n\t$(MAKE) -C libsqlite3_geocoder clean\n\t$(MAKE)\t-C liblwgeom clean\n\t$(MAKE) -C shp2sqlite clean\n\ninstall: all\n\tcp libsqlite3_geocoder/*.so ../lib/geocoder/us/sqlite3.so\n\t$(MAKE) -C shp2sqlite install\n"
  },
  {
    "path": "src/README",
    "content": "What's in this directory\n------------------------\n\nshp2sqlite/\n    A fork of shp2pgsql that generates SQLite 3 compatible\n    output. Used for import.\nliblwgeom/\n    Required by shp2sqlite for converting Shapefiles to WKB.\nlibsqlite3_geocoder/\n    Not actually the geocoder itself, but a library of\n    extensions to SQLite 3 to facilitate geocoding.\nmetaphone/\n    Unused in this project. The metaphone functions have\n    been rolled into libsqlite3_geocoder.\n"
  },
  {
    "path": "src/liblwgeom/Makefile",
    "content": "# **********************************************************************\n# * $Id: Makefile.in \n# *\n# * PostGIS - Spatial Types for PostgreSQL\n# * http://postgis.refractions.net\n# * Copyright 2008 Mark Cave-Ayland\n# *\n# * This is free software; you can redistribute and/or modify it under\n# * the terms of the GNU General Public Licence. See the COPYING file.\n# *\n# **********************************************************************\n\nCC=gcc\nCFLAGS=-g -O2  -fPIC -DPIC  -Wall -Wmissing-prototypes \n\nYACC=yacc\nLEX=flex\n\n# Standalone LWGEOM objects\nSA_OBJS = \\\n\tmeasures.o \\\n\tbox2d.o \\\n\tptarray.o \\\n\tlwgeom_api.o \\\n\tlwgeom.o \\\n\tlwpoint.o \\\n\tlwline.o \\\n\tlwpoly.o \\\n\tlwmpoint.o \\\n\tlwmline.o \\\n\tlwmpoly.o \\\n\tlwcollection.o \\\n\tlwcircstring.o \\\n\tlwcompound.o \\\n\tlwcurvepoly.o \\\n\tlwmcurve.o \\\n\tlwmsurface.o \\\n\tlwutil.o \\\n\tlwalgorithm.o \\\n\tlwgunparse.o \\\n\tlwgparse.o \\\n\tlwsegmentize.o \\\n\twktparse.tab.o \\\n\tlex.yy.o \\\n\tvsprintf.o\t\n\nSA_HEADERS = \\\n\tliblwgeom.h \\\n\tlwalgorithm.h\n\nall: liblwgeom.a\n\nliblwgeom.a: $(SA_OBJS) $(SA_HEADERS) \n\tar rs liblwgeom.a $(SA_OBJS) \t\n\nclean:\n\trm -f $(SA_OBJS) \n\trm -f liblwgeom.a \n\ncheck: liblwgeom.a\n\tmake -C cunit check\n\n# Command to build each of the .o files\n$(SA_OBJS): %.o: %.c \n\t$(CC) $(CFLAGS) -c -o $@ $<\n\n# Commands to generate the lexer and parser from input files\nwktparse.tab.c: wktparse.y\n\t$(YACC) -vd -p lwg_parse_yy wktparse.y\n\tmv -f y.tab.c wktparse.tab.c\n\tmv -f y.tab.h wktparse.tab.h\n \nlex.yy.c: wktparse.lex wktparse.tab.c\n\t$(LEX) -Plwg_parse_yy -i -f -o'lex.yy.c' wktparse.lex\n \n"
  },
  {
    "path": "src/liblwgeom/box2d.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n\n#include \"liblwgeom.h\"\n\n#ifndef EPSILON\n#define EPSILON        1.0E-06\n#endif\n#ifndef FPeq\n#define FPeq(A,B)     (fabs((A) - (B)) <= EPSILON)\n#endif\n\n\n/* Expand given box of 'd' units in all directions */\nvoid\nexpand_box2d(BOX2DFLOAT4 *box, double d)\n{\n\tbox->xmin -= d;\n\tbox->ymin -= d;\n\n\tbox->xmax += d;\n\tbox->ymax += d;\n}\n\n\n/*\n * This has been changed in PostGIS 1.1.2 to\n * check exact equality of values (rather then using\n * the FPeq macro taking into account coordinate drifts).\n */\nchar\nbox2d_same(BOX2DFLOAT4 *box1, BOX2DFLOAT4 *box2)\n{\n\treturn(\t(box1->xmax==box2->xmax) &&\n\t\t(box1->xmin==box2->xmin) &&\n\t\t(box1->ymax==box2->ymax) &&\n\t\t(box1->ymin==box2->ymin));\n#if 0 \n\treturn(FPeq(box1->xmax, box2->xmax) &&\n\t\t\t\t   FPeq(box1->xmin, box2->xmin) &&\n\t\t\t\t   FPeq(box1->ymax, box2->ymax) &&\n\t\t\t\t   FPeq(box1->ymin, box2->ymin));\n#endif\n}\n\nBOX2DFLOAT4 *\nbox2d_clone(const BOX2DFLOAT4 *in)\n{\n\tBOX2DFLOAT4 *ret = lwalloc(sizeof(BOX2DFLOAT4));\n\tmemcpy(ret, in, sizeof(BOX2DFLOAT4));\n\treturn ret;\n}\n"
  },
  {
    "path": "src/liblwgeom/lex.yy.c",
    "content": "#line 2 \"lex.yy.c\"\n\n#line 4 \"lex.yy.c\"\n\n#define  YY_INT_ALIGNED short int\n\n/* A lexical scanner generated by flex */\n\n#define yy_create_buffer lwg_parse_yy_create_buffer\n#define yy_delete_buffer lwg_parse_yy_delete_buffer\n#define yy_flex_debug lwg_parse_yy_flex_debug\n#define yy_init_buffer lwg_parse_yy_init_buffer\n#define yy_flush_buffer lwg_parse_yy_flush_buffer\n#define yy_load_buffer_state lwg_parse_yy_load_buffer_state\n#define yy_switch_to_buffer lwg_parse_yy_switch_to_buffer\n#define yyin lwg_parse_yyin\n#define yyleng lwg_parse_yyleng\n#define yylex lwg_parse_yylex\n#define yylineno lwg_parse_yylineno\n#define yyout lwg_parse_yyout\n#define yyrestart lwg_parse_yyrestart\n#define yytext lwg_parse_yytext\n#define yywrap lwg_parse_yywrap\n#define yyalloc lwg_parse_yyalloc\n#define yyrealloc lwg_parse_yyrealloc\n#define yyfree lwg_parse_yyfree\n\n#define FLEX_SCANNER\n#define YY_FLEX_MAJOR_VERSION 2\n#define YY_FLEX_MINOR_VERSION 5\n#define YY_FLEX_SUBMINOR_VERSION 35\n#if YY_FLEX_SUBMINOR_VERSION > 0\n#define FLEX_BETA\n#endif\n\n/* First, we deal with  platform-specific or compiler-specific issues. */\n\n/* begin standard C headers. */\n#include <stdio.h>\n#include <string.h>\n#include <errno.h>\n#include <stdlib.h>\n\n/* end standard C headers. */\n\n/* flex integer type definitions */\n\n#ifndef FLEXINT_H\n#define FLEXINT_H\n\n/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */\n\n#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L\n\n/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,\n * if you want the limit (max/min) macros for int types. \n */\n#ifndef __STDC_LIMIT_MACROS\n#define __STDC_LIMIT_MACROS 1\n#endif\n\n#include <inttypes.h>\ntypedef int8_t flex_int8_t;\ntypedef uint8_t flex_uint8_t;\ntypedef int16_t flex_int16_t;\ntypedef uint16_t flex_uint16_t;\ntypedef int32_t flex_int32_t;\ntypedef uint32_t flex_uint32_t;\n#else\ntypedef signed char flex_int8_t;\ntypedef short int flex_int16_t;\ntypedef int flex_int32_t;\ntypedef unsigned char flex_uint8_t; \ntypedef unsigned short int flex_uint16_t;\ntypedef unsigned int flex_uint32_t;\n\n/* Limits of integral types. */\n#ifndef INT8_MIN\n#define INT8_MIN               (-128)\n#endif\n#ifndef INT16_MIN\n#define INT16_MIN              (-32767-1)\n#endif\n#ifndef INT32_MIN\n#define INT32_MIN              (-2147483647-1)\n#endif\n#ifndef INT8_MAX\n#define INT8_MAX               (127)\n#endif\n#ifndef INT16_MAX\n#define INT16_MAX              (32767)\n#endif\n#ifndef INT32_MAX\n#define INT32_MAX              (2147483647)\n#endif\n#ifndef UINT8_MAX\n#define UINT8_MAX              (255U)\n#endif\n#ifndef UINT16_MAX\n#define UINT16_MAX             (65535U)\n#endif\n#ifndef UINT32_MAX\n#define UINT32_MAX             (4294967295U)\n#endif\n\n#endif /* ! C99 */\n\n#endif /* ! FLEXINT_H */\n\n#ifdef __cplusplus\n\n/* The \"const\" storage-class-modifier is valid. */\n#define YY_USE_CONST\n\n#else\t/* ! __cplusplus */\n\n/* C99 requires __STDC__ to be defined as 1. */\n#if defined (__STDC__)\n\n#define YY_USE_CONST\n\n#endif\t/* defined (__STDC__) */\n#endif\t/* ! __cplusplus */\n\n#ifdef YY_USE_CONST\n#define yyconst const\n#else\n#define yyconst\n#endif\n\n/* Returned upon end-of-file. */\n#define YY_NULL 0\n\n/* Promotes a possibly negative, possibly signed char to an unsigned\n * integer for use as an array index.  If the signed char is negative,\n * we want to instead treat it as an 8-bit unsigned char, hence the\n * double cast.\n */\n#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)\n\n/* Enter a start condition.  This macro really ought to take a parameter,\n * but we do it the disgusting crufty way forced on us by the ()-less\n * definition of BEGIN.\n */\n#define BEGIN (yy_start) = 1 + 2 *\n\n/* Translate the current start state into a value that can be later handed\n * to BEGIN to return to the state.  The YYSTATE alias is for lex\n * compatibility.\n */\n#define YY_START (((yy_start) - 1) / 2)\n#define YYSTATE YY_START\n\n/* Action number for EOF rule of a given start state. */\n#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)\n\n/* Special action meaning \"start processing a new file\". */\n#define YY_NEW_FILE lwg_parse_yyrestart(lwg_parse_yyin  )\n\n#define YY_END_OF_BUFFER_CHAR 0\n\n/* Size of default input buffer. */\n#ifndef YY_BUF_SIZE\n#define YY_BUF_SIZE 16384\n#endif\n\n/* The state buf must be large enough to hold one state per character in the main buffer.\n */\n#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))\n\n#ifndef YY_TYPEDEF_YY_BUFFER_STATE\n#define YY_TYPEDEF_YY_BUFFER_STATE\ntypedef struct yy_buffer_state *YY_BUFFER_STATE;\n#endif\n\nextern int lwg_parse_yyleng;\n\nextern FILE *lwg_parse_yyin, *lwg_parse_yyout;\n\n#define EOB_ACT_CONTINUE_SCAN 0\n#define EOB_ACT_END_OF_FILE 1\n#define EOB_ACT_LAST_MATCH 2\n\n    #define YY_LESS_LINENO(n)\n    \n/* Return all but the first \"n\" matched characters back to the input stream. */\n#define yyless(n) \\\n\tdo \\\n\t\t{ \\\n\t\t/* Undo effects of setting up lwg_parse_yytext. */ \\\n        int yyless_macro_arg = (n); \\\n        YY_LESS_LINENO(yyless_macro_arg);\\\n\t\t*yy_cp = (yy_hold_char); \\\n\t\tYY_RESTORE_YY_MORE_OFFSET \\\n\t\t(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \\\n\t\tYY_DO_BEFORE_ACTION; /* set up lwg_parse_yytext again */ \\\n\t\t} \\\n\twhile ( 0 )\n\n#define unput(c) yyunput( c, (yytext_ptr)  )\n\n#ifndef YY_TYPEDEF_YY_SIZE_T\n#define YY_TYPEDEF_YY_SIZE_T\ntypedef size_t yy_size_t;\n#endif\n\n#ifndef YY_STRUCT_YY_BUFFER_STATE\n#define YY_STRUCT_YY_BUFFER_STATE\nstruct yy_buffer_state\n\t{\n\tFILE *yy_input_file;\n\n\tchar *yy_ch_buf;\t\t/* input buffer */\n\tchar *yy_buf_pos;\t\t/* current position in input buffer */\n\n\t/* Size of input buffer in bytes, not including room for EOB\n\t * characters.\n\t */\n\tyy_size_t yy_buf_size;\n\n\t/* Number of characters read into yy_ch_buf, not including EOB\n\t * characters.\n\t */\n\tint yy_n_chars;\n\n\t/* Whether we \"own\" the buffer - i.e., we know we created it,\n\t * and can realloc() it to grow it, and should free() it to\n\t * delete it.\n\t */\n\tint yy_is_our_buffer;\n\n\t/* Whether this is an \"interactive\" input source; if so, and\n\t * if we're using stdio for input, then we want to use getc()\n\t * instead of fread(), to make sure we stop fetching input after\n\t * each newline.\n\t */\n\tint yy_is_interactive;\n\n\t/* Whether we're considered to be at the beginning of a line.\n\t * If so, '^' rules will be active on the next match, otherwise\n\t * not.\n\t */\n\tint yy_at_bol;\n\n    int yy_bs_lineno; /**< The line count. */\n    int yy_bs_column; /**< The column count. */\n    \n\t/* Whether to try to fill the input buffer when we reach the\n\t * end of it.\n\t */\n\tint yy_fill_buffer;\n\n\tint yy_buffer_status;\n\n#define YY_BUFFER_NEW 0\n#define YY_BUFFER_NORMAL 1\n\t/* When an EOF's been seen but there's still some text to process\n\t * then we mark the buffer as YY_EOF_PENDING, to indicate that we\n\t * shouldn't try reading from the input source any more.  We might\n\t * still have a bunch of tokens to match, though, because of\n\t * possible backing-up.\n\t *\n\t * When we actually see the EOF, we change the status to \"new\"\n\t * (via lwg_parse_yyrestart()), so that the user can continue scanning by\n\t * just pointing lwg_parse_yyin at a new input file.\n\t */\n#define YY_BUFFER_EOF_PENDING 2\n\n\t};\n#endif /* !YY_STRUCT_YY_BUFFER_STATE */\n\n/* Stack of input buffers. */\nstatic size_t yy_buffer_stack_top = 0; /**< index of top of stack. */\nstatic size_t yy_buffer_stack_max = 0; /**< capacity of stack. */\nstatic YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */\n\n/* We provide macros for accessing buffer states in case in the\n * future we want to put the buffer states in a more general\n * \"scanner state\".\n *\n * Returns the top of the stack, or NULL.\n */\n#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \\\n                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \\\n                          : NULL)\n\n/* Same as previous macro, but useful when we know that the buffer stack is not\n * NULL or when we need an lvalue. For internal use only.\n */\n#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]\n\n/* yy_hold_char holds the character lost when lwg_parse_yytext is formed. */\nstatic char yy_hold_char;\nstatic int yy_n_chars;\t\t/* number of characters read into yy_ch_buf */\nint lwg_parse_yyleng;\n\n/* Points to current character in buffer. */\nstatic char *yy_c_buf_p = (char *) 0;\nstatic int yy_init = 0;\t\t/* whether we need to initialize */\nstatic int yy_start = 0;\t/* start state number */\n\n/* Flag which is used to allow lwg_parse_yywrap()'s to do buffer switches\n * instead of setting up a fresh lwg_parse_yyin.  A bit of a hack ...\n */\nstatic int yy_did_buffer_switch_on_eof;\n\nvoid lwg_parse_yyrestart (FILE *input_file  );\nvoid lwg_parse_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );\nYY_BUFFER_STATE lwg_parse_yy_create_buffer (FILE *file,int size  );\nvoid lwg_parse_yy_delete_buffer (YY_BUFFER_STATE b  );\nvoid lwg_parse_yy_flush_buffer (YY_BUFFER_STATE b  );\nvoid lwg_parse_yypush_buffer_state (YY_BUFFER_STATE new_buffer  );\nvoid lwg_parse_yypop_buffer_state (void );\n\nstatic void lwg_parse_yyensure_buffer_stack (void );\nstatic void lwg_parse_yy_load_buffer_state (void );\nstatic void lwg_parse_yy_init_buffer (YY_BUFFER_STATE b,FILE *file  );\n\n#define YY_FLUSH_BUFFER lwg_parse_yy_flush_buffer(YY_CURRENT_BUFFER )\n\nYY_BUFFER_STATE lwg_parse_yy_scan_buffer (char *base,yy_size_t size  );\nYY_BUFFER_STATE lwg_parse_yy_scan_string (yyconst char *yy_str  );\nYY_BUFFER_STATE lwg_parse_yy_scan_bytes (yyconst char *bytes,int len  );\n\nvoid *lwg_parse_yyalloc (yy_size_t  );\nvoid *lwg_parse_yyrealloc (void *,yy_size_t  );\nvoid lwg_parse_yyfree (void *  );\n\n#define yy_new_buffer lwg_parse_yy_create_buffer\n\n#define yy_set_interactive(is_interactive) \\\n\t{ \\\n\tif ( ! YY_CURRENT_BUFFER ){ \\\n        lwg_parse_yyensure_buffer_stack (); \\\n\t\tYY_CURRENT_BUFFER_LVALUE =    \\\n            lwg_parse_yy_create_buffer(lwg_parse_yyin,YY_BUF_SIZE ); \\\n\t} \\\n\tYY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \\\n\t}\n\n#define yy_set_bol(at_bol) \\\n\t{ \\\n\tif ( ! YY_CURRENT_BUFFER ){\\\n        lwg_parse_yyensure_buffer_stack (); \\\n\t\tYY_CURRENT_BUFFER_LVALUE =    \\\n            lwg_parse_yy_create_buffer(lwg_parse_yyin,YY_BUF_SIZE ); \\\n\t} \\\n\tYY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \\\n\t}\n\n#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)\n\n/* Begin user sect3 */\n\ntypedef char YY_CHAR;\n\nFILE *lwg_parse_yyin = (FILE *) 0, *lwg_parse_yyout = (FILE *) 0;\n\ntypedef int yy_state_type;\n\nextern int lwg_parse_yylineno;\n\nint lwg_parse_yylineno = 1;\n\nextern char *lwg_parse_yytext;\n#define yytext_ptr lwg_parse_yytext\nstatic yyconst flex_int16_t yy_nxt[][128] =\n    {\n    {\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0\n    },\n\n    {\n        5,    6,    6,    6,    6,    6,    6,    6,    6,    7,\n        8,    6,    6,    7,    6,    6,    6,    6,    6,    6,\n        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n        6,    6,    7,    6,    6,    6,    6,    6,    6,    6,\n        9,   10,    6,    6,   11,    6,    6,    6,   12,    6,\n        6,    6,    6,    6,    6,    6,    6,    6,    6,   13,\n        6,   14,    6,    6,    6,    6,    6,   15,    6,   16,\n\n        6,   17,    6,    6,    6,    6,   18,   19,    6,    6,\n       20,    6,    6,   21,    6,    6,    6,    6,    6,    6,\n        6,    6,    6,    6,    6,    6,    6,    6,    6,   15,\n        6,   16,    6,   17,    6,    6,    6,    6,   18,   19,\n        6,    6,   20,    6,    6,   21,    6,    6,    6,    6,\n        6,    6,    6,    6,    6,    6,    6,    6\n    },\n\n    {\n        5,    6,    6,    6,    6,    6,    6,    6,    6,    7,\n        8,    6,    6,    7,    6,    6,    6,    6,    6,    6,\n        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n        6,    6,    7,    6,    6,    6,    6,    6,    6,    6,\n\n        9,   10,    6,    6,   11,    6,    6,    6,   12,    6,\n        6,    6,    6,    6,    6,    6,    6,    6,    6,   13,\n        6,   14,    6,    6,    6,    6,    6,   15,    6,   16,\n        6,   17,    6,    6,    6,    6,   18,   19,    6,    6,\n       20,    6,    6,   21,    6,    6,    6,    6,    6,    6,\n        6,    6,    6,    6,    6,    6,    6,    6,    6,   15,\n        6,   16,    6,   17,    6,    6,    6,    6,   18,   19,\n        6,    6,   20,    6,    6,   21,    6,    6,    6,    6,\n        6,    6,    6,    6,    6,    6,    6,    6\n    },\n\n    {\n        5,    6,    6,    6,    6,    6,    6,    6,    6,    7,\n\n        8,    6,    6,    7,    6,    6,    6,    6,    6,    6,\n        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n        6,    6,    7,    6,    6,    6,    6,    6,    6,    6,\n        9,   10,    6,   22,   11,   22,   23,    6,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,    6,   13,\n        6,   14,    6,    6,    6,    6,    6,   15,    6,   16,\n        6,   17,    6,    6,    6,    6,   18,   19,    6,    6,\n       20,    6,    6,   21,    6,    6,    6,    6,    6,    6,\n        6,    6,    6,    6,    6,    6,    6,    6,    6,   15,\n        6,   16,    6,   17,    6,    6,    6,    6,   18,   19,\n\n        6,    6,   20,    6,    6,   21,    6,    6,    6,    6,\n        6,    6,    6,    6,   22,    6,    6,    6\n    },\n\n    {\n        5,    6,    6,    6,    6,    6,    6,    6,    6,    7,\n        8,    6,    6,    7,    6,    6,    6,    6,    6,    6,\n        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n        6,    6,    7,    6,    6,    6,    6,    6,    6,    6,\n        9,   10,    6,   22,   11,   22,   23,    6,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,    6,   13,\n        6,   14,    6,    6,    6,    6,    6,   15,    6,   16,\n        6,   17,    6,    6,    6,    6,   18,   19,    6,    6,\n\n       20,    6,    6,   21,    6,    6,    6,    6,    6,    6,\n        6,    6,    6,    6,    6,    6,    6,    6,    6,   15,\n        6,   16,    6,   17,    6,    6,    6,    6,   18,   19,\n        6,    6,   20,    6,    6,   21,    6,    6,    6,    6,\n        6,    6,    6,    6,   22,    6,    6,    6\n    },\n\n    {\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5\n    },\n\n    {\n        5,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6\n    },\n\n    {\n        5,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   25,\n       25,   -7,   -7,   25,   -7,   -7,   -7,   -7,   -7,   -7,\n       -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,\n       -7,   -7,   25,   -7,   -7,   -7,   -7,   -7,   -7,   -7,\n       -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,\n       -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,\n       -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,\n       -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,\n       -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,\n\n       -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,\n       -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,\n       -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,\n       -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7\n    },\n\n    {\n        5,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   25,\n       25,   -8,   -8,   25,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   25,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8\n    },\n\n    {\n        5,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9\n\n    },\n\n    {\n        5,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10\n    },\n\n    {\n        5,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11\n    },\n\n    {\n        5,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,   26,   27,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12\n    },\n\n    {\n        5,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13\n    },\n\n    {\n        5,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14\n    },\n\n    {\n        5,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,   28,  -15,  -15,  -15,  -15,  -15,   29,\n      -15,  -15,  -15,  -15,  -15,   30,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,   28,  -15,  -15,  -15,  -15,\n      -15,   29,  -15,  -15,  -15,  -15,  -15,   30,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15\n    },\n\n    {\n        5,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,   31,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,   31,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16\n    },\n\n    {\n        5,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,   32,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,   32,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17\n    },\n\n    {\n        5,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,   33,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,   33,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18\n    },\n\n    {\n        5,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,   34,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,   34,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19\n\n    },\n\n    {\n        5,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,   35,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,   35,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20\n    },\n\n    {\n        5,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,   36,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,   36,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21\n    },\n\n    {\n        5,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n\n      -22,  -22,  -22,  -22,  -22,  -22,   37,  -22,   38,   38,\n       38,   38,   38,   38,   38,   38,   38,   38,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22\n    },\n\n    {\n        5,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,   39,   39,\n       39,   39,   39,   39,   39,   39,   39,   39,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23\n    },\n\n    {\n        5,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,\n      -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,\n      -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,\n      -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,\n      -24,  -24,  -24,  -24,  -24,  -24,   40,  -24,   38,   38,\n       38,   38,   38,   38,   38,   38,   38,   38,  -24,  -24,\n      -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,   41,\n      -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,\n\n      -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,\n      -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,\n      -24,   41,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,\n      -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,\n      -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24\n    },\n\n    {\n        5,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,   25,\n       25,  -25,  -25,   25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,   25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25\n    },\n\n    {\n        5,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,   42,   42,\n       42,   42,   42,   42,   42,   42,   42,   42,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,   42,   42,   42,   42,   42,\n       42,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,   42,   42,   42,\n       42,   42,   42,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26\n    },\n\n    {\n        5,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,   43,   43,\n       43,   43,   43,   43,   43,   43,   43,   43,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,   43,   43,   43,   43,   43,\n       43,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,   43,   43,   43,\n       43,   43,   43,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27\n    },\n\n    {\n        5,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,   44,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,   44,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28\n    },\n\n    {\n        5,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,   45,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,   45,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29\n\n    },\n\n    {\n        5,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,   46,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,   46,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30\n    },\n\n    {\n        5,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n       47,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,   47,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31\n    },\n\n    {\n        5,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,   48,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,   48,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32\n    },\n\n    {\n        5,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,   49,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n\n       49,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33\n    },\n\n    {\n        5,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,   50,  -34,  -34,  -34,\n\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,   50,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34\n    },\n\n    {\n        5,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,   51,  -35,  -35,   52,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,   51,  -35,  -35,   52,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35\n    },\n\n    {\n        5,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,   53,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,   53,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36\n    },\n\n    {\n        5,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,   39,   39,\n       39,   39,   39,   39,   39,   39,   39,   39,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37\n    },\n\n    {\n        5,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,   40,  -38,   38,   38,\n       38,   38,   38,   38,   38,   38,   38,   38,  -38,  -38,\n\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,   41,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,   41,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38\n    },\n\n    {\n        5,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,   39,   39,\n       39,   39,   39,   39,   39,   39,   39,   39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,   54,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,   54,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39\n\n    },\n\n    {\n        5,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,   55,   55,\n       55,   55,   55,   55,   55,   55,   55,   55,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40\n    },\n\n    {\n        5,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,   56,  -41,   56,  -41,  -41,   57,   57,\n       57,   57,   57,   57,   57,   57,   57,   57,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41\n    },\n\n    {\n        5,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,   42,   42,\n       42,   42,   42,   42,   42,   42,   42,   42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,   42,   42,   42,   42,   42,\n       42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,   42,   42,   42,\n       42,   42,   42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42\n    },\n\n    {\n        5,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,   43,   43,\n       43,   43,   43,   43,   43,   43,   43,   43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,   43,   43,   43,   43,   43,\n       43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,   43,   43,   43,\n       43,   43,   43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43\n    },\n\n    {\n        5,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,   58,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,   58,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44\n    },\n\n    {\n        5,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n       59,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,   59,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45\n    },\n\n    {\n        5,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,   60,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,   60,  -46,\n\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46\n    },\n\n    {\n        5,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,   61,  -47,  -47,  -47,  -47,  -47,\n\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,   61,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47\n    },\n\n    {\n        5,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,   62,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,   62,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48\n    },\n\n    {\n        5,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,   63,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,   63,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49\n\n    },\n\n    {\n        5,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,\n      -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,\n      -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,\n      -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,\n      -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,\n      -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,\n      -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,\n      -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,\n      -50,  -50,  -50,  -50,   64,  -50,  -50,  -50,  -50,  -50,\n      -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,\n\n      -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,\n      -50,  -50,  -50,  -50,  -50,  -50,   64,  -50,  -50,  -50,\n      -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50\n    },\n\n    {\n        5,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,\n      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,\n      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,\n      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,\n      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,\n      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,\n      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,\n\n      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,   65,  -51,\n      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,\n      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,\n      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,\n       65,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,\n      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51\n    },\n\n    {\n        5,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,\n      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,\n      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,\n      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,\n\n      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,\n      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,\n      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,\n      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,\n      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,   66,\n      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,\n      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,\n      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,\n      -52,   66,  -52,  -52,  -52,  -52,  -52,  -52\n    },\n\n    {\n        5,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,\n\n      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,\n      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,\n      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,\n      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,\n      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,\n      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,   67,  -53,\n      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,\n      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,\n      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,\n       67,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,\n\n      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,\n      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53\n    },\n\n    {\n        5,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,\n      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,\n      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,\n      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,\n      -54,  -54,  -54,   68,  -54,   68,  -54,  -54,   69,   69,\n       69,   69,   69,   69,   69,   69,   69,   69,  -54,  -54,\n      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,\n      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,\n\n      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,\n      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,\n      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,\n      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,\n      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54\n    },\n\n    {\n        5,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,\n      -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,\n      -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,\n      -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,\n      -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,   55,   55,\n\n       55,   55,   55,   55,   55,   55,   55,   55,  -55,  -55,\n      -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,   41,\n      -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,\n      -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,\n      -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,\n      -55,   41,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,\n      -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,\n      -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55\n    },\n\n    {\n        5,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,\n      -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,\n\n      -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,\n      -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,\n      -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,   57,   57,\n       57,   57,   57,   57,   57,   57,   57,   57,  -56,  -56,\n      -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,\n      -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,\n      -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,\n      -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,\n      -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,\n      -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,\n\n      -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56\n    },\n\n    {\n        5,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,\n      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,\n      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,\n      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,\n      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,   57,   57,\n       57,   57,   57,   57,   57,   57,   57,   57,  -57,  -57,\n      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,\n      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,\n      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,\n\n      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,\n      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,\n      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,\n      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57\n    },\n\n    {\n        5,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,\n      -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,\n      -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,\n      -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,\n      -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,\n      -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,\n\n      -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,\n      -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,\n      -58,  -58,  -58,  -58,  -58,   70,  -58,  -58,  -58,  -58,\n      -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,\n      -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,\n      -58,  -58,  -58,  -58,  -58,  -58,  -58,   70,  -58,  -58,\n      -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58\n    },\n\n    {\n        5,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,\n      -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,\n      -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,\n\n      -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,\n      -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,\n      -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,\n      -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,\n      -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,   71,\n      -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,\n      -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,\n      -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,\n      -59,   71,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,\n      -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59\n\n    },\n\n    {\n        5,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,\n      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,\n      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,\n      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,\n      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,\n      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,\n      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,   72,\n      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,\n      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,\n      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,\n\n      -60,   72,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,\n      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,\n      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60\n    },\n\n    {\n        5,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,\n      -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,\n      -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,\n      -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,\n      -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,\n      -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,\n      -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,\n\n      -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,\n      -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,   73,\n      -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,\n      -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,\n      -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,\n      -61,   73,  -61,  -61,  -61,  -61,  -61,  -61\n    },\n\n    {\n        5,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,\n      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,\n      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,\n      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,\n\n      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,\n      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,\n      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,   74,\n      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,\n      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,\n      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,\n      -62,   74,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,\n      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,\n      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62\n    },\n\n    {\n        5,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,\n\n      -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,\n      -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,\n      -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,\n      -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,\n      -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,\n      -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,\n      -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,\n      -63,  -63,  -63,   75,  -63,  -63,  -63,  -63,  -63,  -63,\n      -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,\n      -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,\n\n      -63,  -63,  -63,  -63,  -63,   75,  -63,  -63,  -63,  -63,\n      -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63\n    },\n\n    {\n        5,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,\n      -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,\n      -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,\n      -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,\n      -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,\n      -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,\n      -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,\n      -64,  -64,  -64,   76,  -64,  -64,  -64,  -64,  -64,  -64,\n\n      -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,\n      -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,\n      -64,  -64,  -64,  -64,  -64,   76,  -64,  -64,  -64,  -64,\n      -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,\n      -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64\n    },\n\n    {\n        5,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,\n      -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,\n      -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,\n      -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,\n      -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,\n\n      -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,\n      -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,\n      -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,\n      -65,  -65,  -65,  -65,   77,  -65,  -65,  -65,  -65,  -65,\n      -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,\n      -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,\n      -65,  -65,  -65,  -65,  -65,  -65,   77,  -65,  -65,  -65,\n      -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65\n    },\n\n    {\n        5,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,\n      -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,\n\n      -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,\n      -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,\n      -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,\n      -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,\n      -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,\n      -66,   78,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,\n      -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,\n      -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,\n      -66,  -66,  -66,   78,  -66,  -66,  -66,  -66,  -66,  -66,\n      -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,\n\n      -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66\n    },\n\n    {\n        5,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,\n      -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67\n    },\n\n    {\n        5,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,\n      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,\n      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,\n      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,\n      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,   69,   69,\n       69,   69,   69,   69,   69,   69,   69,   69,  -68,  -68,\n\n      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,\n      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,\n      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,\n      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,\n      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,\n      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,\n      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68\n    },\n\n    {\n        5,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,\n      -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,\n      -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,\n\n      -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,\n      -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,   69,   69,\n       69,   69,   69,   69,   69,   69,   69,   69,  -69,  -69,\n      -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,\n      -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,\n      -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,\n      -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,\n      -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,\n      -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,\n      -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69\n\n    },\n\n    {\n        5,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,\n      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,\n      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,\n      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,\n      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,\n      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,\n      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,\n      -70,  -70,  -70,  -70,  -70,  -70,   79,  -70,  -70,  -70,\n      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,\n      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,\n\n      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,   79,  -70,\n      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,\n      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70\n    },\n\n    {\n        5,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,\n      -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,\n      -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,\n      -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,\n      -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,\n      -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,\n      -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,\n\n      -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,\n      -71,  -71,  -71,  -71,  -71,   80,  -71,  -71,  -71,  -71,\n      -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,\n      -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,\n      -71,  -71,  -71,  -71,  -71,  -71,  -71,   80,  -71,  -71,\n      -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71\n    },\n\n    {\n        5,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n      -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n      -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n      -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n\n      -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n      -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n      -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n      -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n       81,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n      -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n      -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n      -72,  -72,   81,  -72,  -72,  -72,  -72,  -72,  -72,  -72,\n      -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72\n    },\n\n    {\n        5,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,\n      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73\n    },\n\n    {\n        5,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,\n      -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,\n      -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,\n      -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,\n      -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,\n      -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,\n      -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,\n      -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,\n\n      -74,  -74,  -74,  -74,   82,  -74,  -74,  -74,  -74,  -74,\n      -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,\n      -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,\n      -74,  -74,  -74,  -74,  -74,  -74,   82,  -74,  -74,  -74,\n      -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74\n    },\n\n    {\n        5,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,\n      -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,\n      -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,\n      -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,\n      -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,\n\n      -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,\n      -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,\n      -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,\n      -75,  -75,  -75,  -75,   83,  -75,  -75,  -75,  -75,  -75,\n      -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,\n      -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,\n      -75,  -75,  -75,  -75,  -75,  -75,   83,  -75,  -75,  -75,\n      -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75\n    },\n\n    {\n        5,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,\n      -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,\n\n      -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,\n      -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,\n      -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,\n      -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,\n      -76,  -76,  -76,  -76,  -76,  -76,  -76,   84,  -76,  -76,\n      -76,  -76,  -76,  -76,  -76,  -76,   85,  -76,  -76,  -76,\n       86,  -76,  -76,   87,  -76,  -76,  -76,  -76,  -76,  -76,\n      -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,   84,\n      -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,   85,  -76,\n      -76,  -76,   86,  -76,  -76,   87,  -76,  -76,  -76,  -76,\n\n      -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76\n    },\n\n    {\n        5,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,   88,  -77,  -77,\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,\n\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,   88,\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77,\n      -77,  -77,  -77,  -77,  -77,  -77,  -77,  -77\n    },\n\n    {\n        5,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,\n      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,\n      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,\n      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,\n      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,\n      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,\n\n      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,\n      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,   89,\n      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,\n      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,\n      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,\n      -78,   89,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,\n      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78\n    },\n\n    {\n        5,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,\n      -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,\n      -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,\n\n      -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,\n      -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,\n      -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,\n      -79,  -79,  -79,  -79,  -79,   90,  -79,  -79,  -79,  -79,\n      -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,\n      -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,\n      -79,  -79,  -79,  -79,  -79,  -79,  -79,   90,  -79,  -79,\n      -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,\n      -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,\n      -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79\n\n    },\n\n    {\n        5,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,\n      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,\n      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,\n      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,\n      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,\n      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,\n      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,\n      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,   91,  -80,\n      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,\n      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,\n\n      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,\n       91,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,\n      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80\n    },\n\n    {\n        5,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,\n      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,\n      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,\n      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,\n      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,\n      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,\n      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,\n\n      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,   92,\n      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,\n      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,\n      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,\n      -81,   92,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,\n      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81\n    },\n\n    {\n        5,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,\n      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,\n      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,\n      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,\n\n      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,\n      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,\n      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,\n      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,\n      -82,  -82,   93,  -82,  -82,  -82,  -82,  -82,  -82,  -82,\n      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,\n      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,\n      -82,  -82,  -82,  -82,   93,  -82,  -82,  -82,  -82,  -82,\n      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82\n    },\n\n    {\n        5,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,\n\n      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,\n      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,\n      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,\n      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,\n      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,\n      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,\n      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,\n      -83,  -83,   94,  -83,  -83,  -83,  -83,  -83,  -83,  -83,\n      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,\n      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,\n\n      -83,  -83,  -83,  -83,   94,  -83,  -83,  -83,  -83,  -83,\n      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83\n    },\n\n    {\n        5,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,\n      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,\n      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,\n      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,\n      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,\n      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,\n      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,\n      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,\n\n      -84,  -84,  -84,  -84,  -84,   95,  -84,  -84,  -84,  -84,\n      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,\n      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,\n      -84,  -84,  -84,  -84,  -84,  -84,  -84,   95,  -84,  -84,\n      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84\n    },\n\n    {\n        5,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,\n      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,\n      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,\n      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,\n      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,\n\n      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,\n      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,\n      -85,  -85,  -85,   96,  -85,  -85,  -85,  -85,  -85,  -85,\n      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,\n      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,\n      -85,  -85,  -85,  -85,  -85,   96,  -85,  -85,  -85,  -85,\n      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,\n      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85\n    },\n\n    {\n        5,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,\n      -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,\n\n      -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,\n      -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,\n      -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,\n      -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,\n      -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,\n      -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,   97,\n      -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,\n      -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,\n      -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,\n      -86,   97,  -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86,\n\n      -86,  -86,  -86,  -86,  -86,  -86,  -86,  -86\n    },\n\n    {\n        5,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,\n      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,\n      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,\n      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,\n      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,\n      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,\n      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,\n      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,\n      -87,  -87,  -87,  -87,  -87,   98,  -87,  -87,  -87,  -87,\n\n      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,\n      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,\n      -87,  -87,  -87,  -87,  -87,  -87,  -87,   98,  -87,  -87,\n      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87\n    },\n\n    {\n        5,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,\n      -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88\n    },\n\n    {\n        5,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,\n      -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,\n      -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,\n\n      -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,\n      -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,\n      -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,\n      -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,\n      -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,   99,  -89,\n      -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,\n      -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,\n      -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,\n       99,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,\n      -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89\n\n    },\n\n    {\n        5,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,\n      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,\n      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,\n      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,\n      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,\n      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,\n      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,\n      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,\n      -90,  -90,  100,  -90,  -90,  -90,  -90,  -90,  -90,  -90,\n      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,\n\n      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,\n      -90,  -90,  -90,  -90,  100,  -90,  -90,  -90,  -90,  -90,\n      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90\n    },\n\n    {\n        5,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,\n      -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,\n      -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,\n      -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,\n      -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,\n      -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,\n      -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  101,  -91,\n\n      -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,\n      -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,\n      -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,\n      101,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,\n      -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,\n      -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91\n    },\n\n    {\n        5,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,\n      -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,\n      -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,\n      -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,\n\n      -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,\n      -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,\n      -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,\n      -92,  -92,  -92,  -92,  -92,  -92,  102,  -92,  -92,  -92,\n      -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,\n      -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,\n      -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  102,  -92,\n      -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,\n      -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92\n    },\n\n    {\n        5,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,\n\n      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,\n      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,\n      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,\n      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,\n      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,\n      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,\n      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,\n      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  103,\n      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,\n      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,\n\n      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,\n      -93,  103,  -93,  -93,  -93,  -93,  -93,  -93\n    },\n\n    {\n        5,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,\n      -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,\n      -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,\n      -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,\n      -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,\n      -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,\n      -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,\n      -94,  -94,  -94,  104,  -94,  -94,  -94,  -94,  -94,  -94,\n\n      -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,\n      -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,\n      -94,  -94,  -94,  -94,  -94,  104,  -94,  -94,  -94,  -94,\n      -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,\n      -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94\n    },\n\n    {\n        5,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,\n      -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,\n      -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,\n      -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,\n      -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,\n\n      -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,\n      -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,\n      -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,\n      -95,  -95,  105,  -95,  -95,  -95,  -95,  -95,  -95,  -95,\n      -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,\n      -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,\n      -95,  -95,  -95,  -95,  105,  -95,  -95,  -95,  -95,  -95,\n      -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95\n    },\n\n    {\n        5,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,\n      -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,\n\n      -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,\n      -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,\n      -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,\n      -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,\n      -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,\n      -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  106,  -96,\n      -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,\n      -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,\n      -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,\n      106,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,\n\n      -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96\n    },\n\n    {\n        5,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,\n      -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,\n      -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,\n      -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,\n      -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,\n      -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,\n      -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,\n      -97,  -97,  -97,  107,  -97,  -97,  108,  -97,  -97,  -97,\n      -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,\n\n      -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,\n      -97,  -97,  -97,  -97,  -97,  107,  -97,  -97,  108,  -97,\n      -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,\n      -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97\n    },\n\n    {\n        5,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,\n      -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,\n      -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,\n      -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,\n      -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,\n      -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,\n\n      -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,\n      -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,\n      -98,  -98,  109,  -98,  -98,  -98,  -98,  -98,  -98,  -98,\n      -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,\n      -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,\n      -98,  -98,  -98,  -98,  109,  -98,  -98,  -98,  -98,  -98,\n      -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98\n    },\n\n    {\n        5,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,\n\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  110,  -99,  -99,\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  110,\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,\n      -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99\n\n    },\n\n    {\n        5, -100, -100, -100, -100, -100, -100, -100, -100, -100,\n     -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,\n     -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,\n     -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,\n     -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,\n     -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,\n     -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,\n     -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,\n     -100, -100, -100,  111, -100, -100, -100, -100, -100, -100,\n     -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,\n\n     -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,\n     -100, -100, -100, -100, -100,  111, -100, -100, -100, -100,\n     -100, -100, -100, -100, -100, -100, -100, -100\n    },\n\n    {\n        5, -101, -101, -101, -101, -101, -101, -101, -101, -101,\n     -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,\n     -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,\n     -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,\n     -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,\n     -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,\n     -101, -101, -101, -101, -101, -101, -101,  112, -101, -101,\n\n     -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,\n     -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,\n     -101, -101, -101, -101, -101, -101, -101, -101, -101,  112,\n     -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,\n     -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,\n     -101, -101, -101, -101, -101, -101, -101, -101\n    },\n\n    {\n        5, -102, -102, -102, -102, -102, -102, -102, -102, -102,\n     -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,\n     -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,\n     -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,\n\n     -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,\n     -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,\n     -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,\n     -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,\n     -102, -102, -102, -102, -102, -102, -102, -102, -102,  113,\n     -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,\n     -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,\n     -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,\n     -102,  113, -102, -102, -102, -102, -102, -102\n    },\n\n    {\n        5, -103, -103, -103, -103, -103, -103, -103, -103, -103,\n\n     -103, -103, -103, -103, -103, -103, -103, -103, -103, -103,\n     -103, -103, -103, -103, -103, -103, -103, -103, -103, -103,\n     -103, -103, -103, -103, -103, -103, -103, -103, -103, -103,\n     -103, -103, -103, -103, -103, -103, -103, -103, -103, -103,\n     -103, -103, -103, -103, -103, -103, -103, -103, -103, -103,\n     -103, -103, -103, -103, -103, -103, -103,  114, -103, -103,\n     -103, -103, -103, -103, -103, -103, -103, -103, -103, -103,\n     -103, -103, -103, -103, -103, -103, -103, -103, -103, -103,\n     -103, -103, -103, -103, -103, -103, -103, -103, -103,  114,\n     -103, -103, -103, -103, -103, -103, -103, -103, -103, -103,\n\n     -103, -103, -103, -103, -103, -103, -103, -103, -103, -103,\n     -103, -103, -103, -103, -103, -103, -103, -103\n    },\n\n    {\n        5, -104, -104, -104, -104, -104, -104, -104, -104, -104,\n     -104, -104, -104, -104, -104, -104, -104, -104, -104, -104,\n     -104, -104, -104, -104, -104, -104, -104, -104, -104, -104,\n     -104, -104, -104, -104, -104, -104, -104, -104, -104, -104,\n     -104, -104, -104, -104, -104, -104, -104, -104, -104, -104,\n     -104, -104, -104, -104, -104, -104, -104, -104, -104, -104,\n     -104, -104, -104, -104, -104, -104, -104, -104, -104, -104,\n     -104, -104, -104, -104, -104, -104, -104, -104,  115, -104,\n\n     -104, -104, -104, -104, -104, -104, -104, -104, -104, -104,\n     -104, -104, -104, -104, -104, -104, -104, -104, -104, -104,\n     -104, -104, -104, -104, -104, -104, -104, -104, -104, -104,\n      115, -104, -104, -104, -104, -104, -104, -104, -104, -104,\n     -104, -104, -104, -104, -104, -104, -104, -104\n    },\n\n    {\n        5, -105, -105, -105, -105, -105, -105, -105, -105, -105,\n     -105, -105, -105, -105, -105, -105, -105, -105, -105, -105,\n     -105, -105, -105, -105, -105, -105, -105, -105, -105, -105,\n     -105, -105, -105, -105, -105, -105, -105, -105, -105, -105,\n     -105, -105, -105, -105, -105, -105, -105, -105, -105, -105,\n\n     -105, -105, -105, -105, -105, -105, -105, -105, -105, -105,\n     -105, -105, -105, -105, -105, -105, -105, -105, -105, -105,\n     -105, -105, -105, -105, -105, -105, -105, -105, -105, -105,\n     -105, -105, -105, -105, -105, -105,  116, -105, -105, -105,\n     -105, -105, -105, -105, -105, -105, -105, -105, -105, -105,\n     -105, -105, -105, -105, -105, -105, -105, -105, -105, -105,\n     -105, -105, -105, -105, -105, -105, -105, -105,  116, -105,\n     -105, -105, -105, -105, -105, -105, -105, -105\n    },\n\n    {\n        5, -106, -106, -106, -106, -106, -106, -106, -106, -106,\n     -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,\n\n     -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,\n     -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,\n     -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,\n     -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,\n     -106, -106, -106, -106, -106, -106, -106, -106, -106,  117,\n     -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,\n     -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,\n     -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,\n     -106,  117, -106, -106, -106, -106, -106, -106, -106, -106,\n     -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,\n\n     -106, -106, -106, -106, -106, -106, -106, -106\n    },\n\n    {\n        5, -107, -107, -107, -107, -107, -107, -107, -107, -107,\n     -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,\n     -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,\n     -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,\n     -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,\n     -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,\n     -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,\n     -107, -107, -107, -107, -107, -107, -107, -107,  118, -107,\n     -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,\n\n     -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,\n     -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,\n      118, -107, -107, -107, -107, -107, -107, -107, -107, -107,\n     -107, -107, -107, -107, -107, -107, -107, -107\n    },\n\n    {\n        5, -108, -108, -108, -108, -108, -108, -108, -108, -108,\n     -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,\n     -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,\n     -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,\n     -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,\n     -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,\n\n     -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,\n     -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,\n     -108, -108, -108, -108, -108, -108, -108, -108, -108,  119,\n     -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,\n     -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,\n     -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,\n     -108,  119, -108, -108, -108, -108, -108, -108\n    },\n\n    {\n        5, -109, -109, -109, -109, -109, -109, -109, -109, -109,\n     -109, -109, -109, -109, -109, -109, -109, -109, -109, -109,\n     -109, -109, -109, -109, -109, -109, -109, -109, -109, -109,\n\n     -109, -109, -109, -109, -109, -109, -109, -109, -109, -109,\n     -109, -109, -109, -109, -109, -109, -109, -109, -109, -109,\n     -109, -109, -109, -109, -109, -109, -109, -109, -109, -109,\n     -109, -109, -109, -109, -109, -109, -109, -109, -109, -109,\n      120, -109, -109, -109, -109, -109, -109, -109, -109, -109,\n     -109, -109, -109, -109, -109, -109, -109, -109, -109, -109,\n     -109, -109, -109, -109, -109, -109, -109, -109, -109, -109,\n     -109, -109,  120, -109, -109, -109, -109, -109, -109, -109,\n     -109, -109, -109, -109, -109, -109, -109, -109, -109, -109,\n     -109, -109, -109, -109, -109, -109, -109, -109\n\n    },\n\n    {\n        5, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n     -110, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n     -110, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n     -110, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n     -110, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n     -110, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n     -110, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n     -110, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n     -110, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n     -110, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n\n     -110, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n     -110, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n     -110, -110, -110, -110, -110, -110, -110, -110\n    },\n\n    {\n        5, -111, -111, -111, -111, -111, -111, -111, -111, -111,\n     -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,\n     -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,\n     -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,\n     -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,\n     -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,\n     -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,\n\n     -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,\n     -111, -111, -111, -111,  121, -111, -111, -111, -111, -111,\n     -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,\n     -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,\n     -111, -111, -111, -111, -111, -111,  121, -111, -111, -111,\n     -111, -111, -111, -111, -111, -111, -111, -111\n    },\n\n    {\n        5, -112, -112, -112, -112, -112, -112, -112, -112, -112,\n     -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,\n     -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,\n     -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,\n\n     -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,\n     -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,\n     -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,\n     -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,\n     -112, -112, -112, -112, -112,  122, -112, -112, -112, -112,\n     -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,\n     -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,\n     -112, -112, -112, -112, -112, -112, -112,  122, -112, -112,\n     -112, -112, -112, -112, -112, -112, -112, -112\n    },\n\n    {\n        5, -113, -113, -113, -113, -113, -113, -113, -113, -113,\n\n     -113, -113, -113, -113, -113, -113, -113, -113, -113, -113,\n     -113, -113, -113, -113, -113, -113, -113, -113, -113, -113,\n     -113, -113, -113, -113, -113, -113, -113, -113, -113, -113,\n     -113, -113, -113, -113, -113, -113, -113, -113, -113, -113,\n     -113, -113, -113, -113, -113, -113, -113, -113, -113, -113,\n     -113, -113, -113, -113, -113, -113, -113, -113, -113, -113,\n     -113,  123, -113, -113, -113, -113, -113, -113, -113, -113,\n     -113, -113, -113, -113, -113, -113, -113, -113, -113, -113,\n     -113, -113, -113, -113, -113, -113, -113, -113, -113, -113,\n     -113, -113, -113,  123, -113, -113, -113, -113, -113, -113,\n\n     -113, -113, -113, -113, -113, -113, -113, -113, -113, -113,\n     -113, -113, -113, -113, -113, -113, -113, -113\n    },\n\n    {\n        5, -114, -114, -114, -114, -114, -114, -114, -114, -114,\n     -114, -114, -114, -114, -114, -114, -114, -114, -114, -114,\n     -114, -114, -114, -114, -114, -114, -114, -114, -114, -114,\n     -114, -114, -114, -114, -114, -114, -114, -114, -114, -114,\n     -114, -114, -114, -114, -114, -114, -114, -114, -114, -114,\n     -114, -114, -114, -114, -114, -114, -114, -114, -114, -114,\n     -114, -114, -114, -114, -114, -114, -114, -114, -114, -114,\n     -114, -114, -114, -114, -114, -114, -114, -114, -114,  124,\n\n     -114, -114, -114, -114, -114, -114, -114, -114, -114, -114,\n     -114, -114, -114, -114, -114, -114, -114, -114, -114, -114,\n     -114, -114, -114, -114, -114, -114, -114, -114, -114, -114,\n     -114,  124, -114, -114, -114, -114, -114, -114, -114, -114,\n     -114, -114, -114, -114, -114, -114, -114, -114\n    },\n\n    {\n        5, -115, -115, -115, -115, -115, -115, -115, -115, -115,\n     -115, -115, -115, -115, -115, -115, -115, -115, -115, -115,\n     -115, -115, -115, -115, -115, -115, -115, -115, -115, -115,\n     -115, -115, -115, -115, -115, -115, -115, -115, -115, -115,\n     -115, -115, -115, -115, -115, -115, -115, -115, -115, -115,\n\n     -115, -115, -115, -115, -115, -115, -115, -115, -115, -115,\n     -115, -115, -115, -115, -115, -115, -115, -115, -115, -115,\n     -115,  125, -115, -115, -115, -115, -115, -115, -115, -115,\n     -115, -115, -115, -115, -115, -115, -115, -115, -115, -115,\n     -115, -115, -115, -115, -115, -115, -115, -115, -115, -115,\n     -115, -115, -115,  125, -115, -115, -115, -115, -115, -115,\n     -115, -115, -115, -115, -115, -115, -115, -115, -115, -115,\n     -115, -115, -115, -115, -115, -115, -115, -115\n    },\n\n    {\n        5, -116, -116, -116, -116, -116, -116, -116, -116, -116,\n     -116, -116, -116, -116, -116, -116, -116, -116, -116, -116,\n\n     -116, -116, -116, -116, -116, -116, -116, -116, -116, -116,\n     -116, -116, -116, -116, -116, -116, -116, -116, -116, -116,\n     -116, -116, -116, -116, -116, -116, -116, -116, -116, -116,\n     -116, -116, -116, -116, -116, -116, -116, -116, -116, -116,\n     -116, -116, -116, -116, -116, -116, -116, -116, -116,  126,\n     -116, -116, -116, -116, -116, -116, -116, -116, -116, -116,\n     -116, -116, -116, -116, -116, -116, -116, -116, -116, -116,\n     -116, -116, -116, -116, -116, -116, -116, -116, -116, -116,\n     -116,  126, -116, -116, -116, -116, -116, -116, -116, -116,\n     -116, -116, -116, -116, -116, -116, -116, -116, -116, -116,\n\n     -116, -116, -116, -116, -116, -116, -116, -116\n    },\n\n    {\n        5, -117, -117, -117, -117, -117, -117, -117, -117, -117,\n     -117, -117, -117, -117, -117, -117, -117, -117, -117, -117,\n     -117, -117, -117, -117, -117, -117, -117, -117, -117, -117,\n     -117, -117, -117, -117, -117, -117, -117, -117, -117, -117,\n     -117, -117, -117, -117, -117, -117, -117, -117, -117, -117,\n     -117, -117, -117, -117, -117, -117, -117, -117, -117, -117,\n     -117, -117, -117, -117, -117, -117, -117, -117, -117, -117,\n     -117, -117, -117, -117, -117, -117, -117, -117, -117, -117,\n     -117, -117, -117,  127, -117, -117, -117, -117, -117, -117,\n\n     -117, -117, -117, -117, -117, -117, -117, -117, -117, -117,\n     -117, -117, -117, -117, -117, -117, -117, -117, -117, -117,\n     -117, -117, -117, -117, -117,  127, -117, -117, -117, -117,\n     -117, -117, -117, -117, -117, -117, -117, -117\n    },\n\n    {\n        5, -118, -118, -118, -118, -118, -118, -118, -118, -118,\n     -118, -118, -118, -118, -118, -118, -118, -118, -118, -118,\n     -118, -118, -118, -118, -118, -118, -118, -118, -118, -118,\n     -118, -118, -118, -118, -118, -118, -118, -118, -118, -118,\n     -118, -118, -118, -118, -118, -118, -118, -118, -118, -118,\n     -118, -118, -118, -118, -118, -118, -118, -118, -118, -118,\n\n     -118, -118, -118, -118, -118, -118, -118, -118, -118, -118,\n     -118, -118, -118, -118, -118, -118, -118, -118, -118, -118,\n     -118, -118, -118, -118,  128, -118, -118, -118, -118, -118,\n     -118, -118, -118, -118, -118, -118, -118, -118, -118, -118,\n     -118, -118, -118, -118, -118, -118, -118, -118, -118, -118,\n     -118, -118, -118, -118, -118, -118,  128, -118, -118, -118,\n     -118, -118, -118, -118, -118, -118, -118, -118\n    },\n\n    {\n        5, -119, -119, -119, -119, -119, -119, -119, -119, -119,\n     -119, -119, -119, -119, -119, -119, -119, -119, -119, -119,\n     -119, -119, -119, -119, -119, -119, -119, -119, -119, -119,\n\n     -119, -119, -119, -119, -119, -119, -119, -119, -119, -119,\n     -119, -119, -119, -119, -119, -119, -119, -119, -119, -119,\n     -119, -119, -119, -119, -119, -119, -119, -119, -119, -119,\n     -119, -119, -119, -119, -119, -119, -119, -119, -119, -119,\n     -119,  129, -119, -119, -119, -119, -119, -119, -119, -119,\n     -119, -119, -119, -119, -119, -119, -119, -119, -119, -119,\n     -119, -119, -119, -119, -119, -119, -119, -119, -119, -119,\n     -119, -119, -119,  129, -119, -119, -119, -119, -119, -119,\n     -119, -119, -119, -119, -119, -119, -119, -119, -119, -119,\n     -119, -119, -119, -119, -119, -119, -119, -119\n\n    },\n\n    {\n        5, -120, -120, -120, -120, -120, -120, -120, -120, -120,\n     -120, -120, -120, -120, -120, -120, -120, -120, -120, -120,\n     -120, -120, -120, -120, -120, -120, -120, -120, -120, -120,\n     -120, -120, -120, -120, -120, -120, -120, -120, -120, -120,\n     -120, -120, -120, -120, -120, -120, -120, -120, -120, -120,\n     -120, -120, -120, -120, -120, -120, -120, -120, -120, -120,\n     -120, -120, -120, -120, -120,  130, -120, -120, -120, -120,\n     -120, -120, -120, -120, -120, -120, -120, -120, -120, -120,\n     -120, -120, -120, -120, -120, -120, -120, -120, -120, -120,\n     -120, -120, -120, -120, -120, -120, -120,  130, -120, -120,\n\n     -120, -120, -120, -120, -120, -120, -120, -120, -120, -120,\n     -120, -120, -120, -120, -120, -120, -120, -120, -120, -120,\n     -120, -120, -120, -120, -120, -120, -120, -120\n    },\n\n    {\n        5, -121, -121, -121, -121, -121, -121, -121, -121, -121,\n     -121, -121, -121, -121, -121, -121, -121, -121, -121, -121,\n     -121, -121, -121, -121, -121, -121, -121, -121, -121, -121,\n     -121, -121, -121, -121, -121, -121, -121, -121, -121, -121,\n     -121, -121, -121, -121, -121, -121, -121, -121, -121, -121,\n     -121, -121, -121, -121, -121, -121, -121, -121, -121, -121,\n     -121, -121, -121, -121, -121, -121, -121, -121, -121, -121,\n\n     -121, -121, -121, -121, -121, -121, -121, -121, -121, -121,\n     -121, -121,  131, -121, -121, -121, -121, -121, -121, -121,\n     -121, -121, -121, -121, -121, -121, -121, -121, -121, -121,\n     -121, -121, -121, -121, -121, -121, -121, -121, -121, -121,\n     -121, -121, -121, -121,  131, -121, -121, -121, -121, -121,\n     -121, -121, -121, -121, -121, -121, -121, -121\n    },\n\n    {\n        5, -122, -122, -122, -122, -122, -122, -122, -122, -122,\n     -122, -122, -122, -122, -122, -122, -122, -122, -122, -122,\n     -122, -122, -122, -122, -122, -122, -122, -122, -122, -122,\n     -122, -122, -122, -122, -122, -122, -122, -122, -122, -122,\n\n     -122, -122, -122, -122, -122, -122, -122, -122, -122, -122,\n     -122, -122, -122, -122, -122, -122, -122, -122, -122, -122,\n     -122, -122, -122, -122, -122, -122, -122, -122, -122, -122,\n     -122, -122, -122, -122, -122, -122, -122, -122, -122, -122,\n     -122, -122,  132, -122, -122, -122, -122, -122, -122, -122,\n     -122, -122, -122, -122, -122, -122, -122, -122, -122, -122,\n     -122, -122, -122, -122, -122, -122, -122, -122, -122, -122,\n     -122, -122, -122, -122,  132, -122, -122, -122, -122, -122,\n     -122, -122, -122, -122, -122, -122, -122, -122\n    },\n\n    {\n        5, -123, -123, -123, -123, -123, -123, -123, -123, -123,\n\n     -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,\n     -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,\n     -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,\n     -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,\n     -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,\n     -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,\n     -123, -123, -123, -123, -123, -123, -123, -123, -123,  133,\n     -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,\n     -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,\n     -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,\n\n     -123,  133, -123, -123, -123, -123, -123, -123, -123, -123,\n     -123, -123, -123, -123, -123, -123, -123, -123\n    },\n\n    {\n        5, -124, -124, -124, -124, -124, -124, -124, -124, -124,\n     -124, -124, -124, -124, -124, -124, -124, -124, -124, -124,\n     -124, -124, -124, -124, -124, -124, -124, -124, -124, -124,\n     -124, -124, -124, -124, -124, -124, -124, -124, -124, -124,\n     -124, -124, -124, -124, -124, -124, -124, -124, -124, -124,\n     -124, -124, -124, -124, -124, -124, -124, -124, -124, -124,\n     -124, -124, -124, -124, -124, -124, -124, -124, -124, -124,\n     -124, -124, -124, -124, -124, -124,  134, -124, -124, -124,\n\n     -124, -124, -124, -124, -124, -124, -124, -124, -124, -124,\n     -124, -124, -124, -124, -124, -124, -124, -124, -124, -124,\n     -124, -124, -124, -124, -124, -124, -124, -124,  134, -124,\n     -124, -124, -124, -124, -124, -124, -124, -124, -124, -124,\n     -124, -124, -124, -124, -124, -124, -124, -124\n    },\n\n    {\n        5, -125, -125, -125, -125, -125, -125, -125, -125, -125,\n     -125, -125, -125, -125, -125, -125, -125, -125, -125, -125,\n     -125, -125, -125, -125, -125, -125, -125, -125, -125, -125,\n     -125, -125, -125, -125, -125, -125, -125, -125, -125, -125,\n     -125, -125, -125, -125, -125, -125, -125, -125, -125, -125,\n\n     -125, -125, -125, -125, -125, -125, -125, -125, -125, -125,\n     -125, -125, -125, -125, -125, -125, -125, -125, -125, -125,\n     -125, -125, -125, -125, -125, -125, -125,  135, -125, -125,\n     -125, -125, -125, -125, -125, -125, -125, -125, -125, -125,\n     -125, -125, -125, -125, -125, -125, -125, -125, -125, -125,\n     -125, -125, -125, -125, -125, -125, -125, -125, -125,  135,\n     -125, -125, -125, -125, -125, -125, -125, -125, -125, -125,\n     -125, -125, -125, -125, -125, -125, -125, -125\n    },\n\n    {\n        5, -126, -126, -126, -126, -126, -126, -126, -126, -126,\n     -126, -126, -126, -126, -126, -126, -126, -126, -126, -126,\n\n     -126, -126, -126, -126, -126, -126, -126, -126, -126, -126,\n     -126, -126, -126, -126, -126, -126, -126, -126, -126, -126,\n     -126, -126, -126, -126, -126, -126, -126, -126, -126, -126,\n     -126, -126, -126, -126, -126, -126, -126, -126, -126, -126,\n     -126, -126, -126, -126, -126, -126, -126, -126, -126, -126,\n     -126, -126, -126, -126, -126, -126, -126,  136, -126, -126,\n     -126, -126, -126, -126, -126, -126, -126, -126, -126, -126,\n     -126, -126, -126, -126, -126, -126, -126, -126, -126, -126,\n     -126, -126, -126, -126, -126, -126, -126, -126, -126,  136,\n     -126, -126, -126, -126, -126, -126, -126, -126, -126, -126,\n\n     -126, -126, -126, -126, -126, -126, -126, -126\n    },\n\n    {\n        5, -127, -127, -127, -127, -127, -127, -127, -127, -127,\n     -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,\n     -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,\n     -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,\n     -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,\n     -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,\n     -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,\n     -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,\n     -127, -127, -127, -127,  137, -127, -127, -127, -127, -127,\n\n     -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,\n     -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,\n     -127, -127, -127, -127, -127, -127,  137, -127, -127, -127,\n     -127, -127, -127, -127, -127, -127, -127, -127\n    },\n\n    {\n        5, -128, -128, -128, -128, -128, -128, -128, -128, -128,\n     -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,\n     -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,\n     -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,\n     -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,\n     -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,\n\n     -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,\n     -128, -128, -128, -128, -128, -128, -128,  138, -128, -128,\n     -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,\n     -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,\n     -128, -128, -128, -128, -128, -128, -128, -128, -128,  138,\n     -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,\n     -128, -128, -128, -128, -128, -128, -128, -128\n    },\n\n    {\n        5, -129, -129, -129, -129, -129, -129, -129, -129, -129,\n     -129, -129, -129, -129, -129, -129, -129, -129, -129, -129,\n     -129, -129, -129, -129, -129, -129, -129, -129, -129, -129,\n\n     -129, -129, -129, -129, -129, -129, -129, -129, -129, -129,\n     -129, -129, -129, -129, -129, -129, -129, -129, -129, -129,\n     -129, -129, -129, -129, -129, -129, -129, -129, -129, -129,\n     -129, -129, -129, -129, -129, -129, -129, -129, -129, -129,\n     -129, -129, -129, -129, -129, -129, -129, -129, -129,  139,\n     -129, -129, -129, -129, -129, -129, -129, -129, -129, -129,\n     -129, -129, -129, -129, -129, -129, -129, -129, -129, -129,\n     -129, -129, -129, -129, -129, -129, -129, -129, -129, -129,\n     -129,  139, -129, -129, -129, -129, -129, -129, -129, -129,\n     -129, -129, -129, -129, -129, -129, -129, -129\n\n    },\n\n    {\n        5, -130, -130, -130, -130, -130, -130, -130, -130, -130,\n     -130, -130, -130, -130, -130, -130, -130, -130, -130, -130,\n     -130, -130, -130, -130, -130, -130, -130, -130, -130, -130,\n     -130, -130, -130, -130, -130, -130, -130, -130, -130, -130,\n     -130, -130, -130, -130, -130, -130, -130, -130, -130, -130,\n     -130, -130, -130, -130, -130, -130, -130, -130, -130, -130,\n     -130, -130, -130, -130, -130, -130, -130,  140, -130, -130,\n     -130, -130, -130, -130, -130, -130, -130, -130, -130, -130,\n     -130, -130, -130, -130, -130, -130, -130, -130, -130, -130,\n     -130, -130, -130, -130, -130, -130, -130, -130, -130,  140,\n\n     -130, -130, -130, -130, -130, -130, -130, -130, -130, -130,\n     -130, -130, -130, -130, -130, -130, -130, -130, -130, -130,\n     -130, -130, -130, -130, -130, -130, -130, -130\n    },\n\n    {\n        5, -131, -131, -131, -131, -131, -131, -131, -131, -131,\n     -131, -131, -131, -131, -131, -131, -131, -131, -131, -131,\n     -131, -131, -131, -131, -131, -131, -131, -131, -131, -131,\n     -131, -131, -131, -131, -131, -131, -131, -131, -131, -131,\n     -131, -131, -131, -131, -131, -131, -131, -131, -131, -131,\n     -131, -131, -131, -131, -131, -131, -131, -131, -131, -131,\n     -131, -131, -131, -131, -131, -131, -131, -131, -131, -131,\n\n     -131, -131, -131,  141, -131, -131, -131, -131, -131, -131,\n     -131, -131, -131, -131, -131, -131, -131, -131, -131, -131,\n     -131, -131, -131, -131, -131, -131, -131, -131, -131, -131,\n     -131, -131, -131, -131, -131,  141, -131, -131, -131, -131,\n     -131, -131, -131, -131, -131, -131, -131, -131, -131, -131,\n     -131, -131, -131, -131, -131, -131, -131, -131\n    },\n\n    {\n        5, -132, -132, -132, -132, -132, -132, -132, -132, -132,\n     -132, -132, -132, -132, -132, -132, -132, -132, -132, -132,\n     -132, -132, -132, -132, -132, -132, -132, -132, -132, -132,\n     -132, -132, -132, -132, -132, -132, -132, -132, -132, -132,\n\n     -132, -132, -132, -132, -132, -132, -132, -132, -132, -132,\n     -132, -132, -132, -132, -132, -132, -132, -132, -132, -132,\n     -132, -132, -132, -132, -132, -132, -132, -132, -132, -132,\n     -132, -132, -132, -132, -132, -132, -132, -132, -132, -132,\n     -132, -132, -132, -132, -132, -132,  142, -132, -132, -132,\n     -132, -132, -132, -132, -132, -132, -132, -132, -132, -132,\n     -132, -132, -132, -132, -132, -132, -132, -132, -132, -132,\n     -132, -132, -132, -132, -132, -132, -132, -132,  142, -132,\n     -132, -132, -132, -132, -132, -132, -132, -132\n    },\n\n    {\n        5, -133, -133, -133, -133, -133, -133, -133, -133, -133,\n\n     -133, -133, -133, -133, -133, -133, -133, -133, -133, -133,\n     -133, -133, -133, -133, -133, -133, -133, -133, -133, -133,\n     -133, -133, -133, -133, -133, -133, -133, -133, -133, -133,\n     -133, -133, -133, -133, -133, -133, -133, -133, -133, -133,\n     -133, -133, -133, -133, -133, -133, -133, -133, -133, -133,\n     -133, -133, -133, -133, -133, -133, -133, -133, -133, -133,\n     -133, -133, -133, -133, -133, -133, -133, -133,  143, -133,\n     -133, -133, -133, -133, -133, -133, -133, -133, -133, -133,\n     -133, -133, -133, -133, -133, -133, -133, -133, -133, -133,\n     -133, -133, -133, -133, -133, -133, -133, -133, -133, -133,\n\n      143, -133, -133, -133, -133, -133, -133, -133, -133, -133,\n     -133, -133, -133, -133, -133, -133, -133, -133\n    },\n\n    {\n        5, -134, -134, -134, -134, -134, -134, -134, -134, -134,\n     -134, -134, -134, -134, -134, -134, -134, -134, -134, -134,\n     -134, -134, -134, -134, -134, -134, -134, -134, -134, -134,\n     -134, -134, -134, -134, -134, -134, -134, -134, -134, -134,\n     -134, -134, -134, -134, -134, -134, -134, -134, -134, -134,\n     -134, -134, -134, -134, -134, -134, -134, -134, -134, -134,\n     -134, -134, -134, -134, -134, -134, -134, -134, -134, -134,\n     -134, -134, -134, -134, -134, -134,  144, -134, -134, -134,\n\n     -134, -134, -134, -134, -134, -134, -134, -134, -134, -134,\n     -134, -134, -134, -134, -134, -134, -134, -134, -134, -134,\n     -134, -134, -134, -134, -134, -134, -134, -134,  144, -134,\n     -134, -134, -134, -134, -134, -134, -134, -134, -134, -134,\n     -134, -134, -134, -134, -134, -134, -134, -134\n    },\n\n    {\n        5, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n     -135, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n     -135, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n     -135, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n     -135, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n\n     -135, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n     -135, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n     -135, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n     -135, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n     -135, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n     -135, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n     -135, -135, -135, -135, -135, -135, -135, -135, -135, -135,\n     -135, -135, -135, -135, -135, -135, -135, -135\n    },\n\n    {\n        5, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n     -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n\n     -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n     -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n     -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n     -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n     -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n     -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n     -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n     -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n     -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n     -136, -136, -136, -136, -136, -136, -136, -136, -136, -136,\n\n     -136, -136, -136, -136, -136, -136, -136, -136\n    },\n\n    {\n        5, -137, -137, -137, -137, -137, -137, -137, -137, -137,\n     -137, -137, -137, -137, -137, -137, -137, -137, -137, -137,\n     -137, -137, -137, -137, -137, -137, -137, -137, -137, -137,\n     -137, -137, -137, -137, -137, -137, -137, -137, -137, -137,\n     -137, -137, -137, -137, -137, -137, -137, -137, -137, -137,\n     -137, -137, -137, -137, -137, -137, -137, -137, -137, -137,\n     -137, -137, -137, -137, -137, -137, -137, -137, -137, -137,\n     -137, -137, -137, -137, -137, -137, -137, -137, -137, -137,\n     -137, -137,  145, -137, -137, -137, -137, -137, -137, -137,\n\n     -137, -137, -137, -137, -137, -137, -137, -137, -137, -137,\n     -137, -137, -137, -137, -137, -137, -137, -137, -137, -137,\n     -137, -137, -137, -137,  145, -137, -137, -137, -137, -137,\n     -137, -137, -137, -137, -137, -137, -137, -137\n    },\n\n    {\n        5, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n     -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n     -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n     -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n     -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n     -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n\n     -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n     -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n     -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n     -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n     -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n     -138, -138, -138, -138, -138, -138, -138, -138, -138, -138,\n     -138, -138, -138, -138, -138, -138, -138, -138\n    },\n\n    {\n        5, -139, -139, -139, -139, -139, -139, -139, -139, -139,\n     -139, -139, -139, -139, -139, -139, -139, -139, -139, -139,\n     -139, -139, -139, -139, -139, -139, -139, -139, -139, -139,\n\n     -139, -139, -139, -139, -139, -139, -139, -139, -139, -139,\n     -139, -139, -139, -139, -139, -139, -139, -139, -139, -139,\n     -139, -139, -139, -139, -139, -139, -139, -139, -139, -139,\n     -139, -139, -139, -139, -139, -139, -139, -139, -139, -139,\n     -139, -139, -139, -139, -139, -139, -139, -139,  146, -139,\n     -139, -139, -139, -139, -139, -139, -139, -139, -139, -139,\n     -139, -139, -139, -139, -139, -139, -139, -139, -139, -139,\n     -139, -139, -139, -139, -139, -139, -139, -139, -139, -139,\n      146, -139, -139, -139, -139, -139, -139, -139, -139, -139,\n     -139, -139, -139, -139, -139, -139, -139, -139\n\n    },\n\n    {\n        5, -140, -140, -140, -140, -140, -140, -140, -140, -140,\n     -140, -140, -140, -140, -140, -140, -140, -140, -140, -140,\n     -140, -140, -140, -140, -140, -140, -140, -140, -140, -140,\n     -140, -140, -140, -140, -140, -140, -140, -140, -140, -140,\n     -140, -140, -140, -140, -140, -140, -140, -140, -140, -140,\n     -140, -140, -140, -140, -140, -140, -140, -140, -140, -140,\n     -140, -140, -140, -140, -140, -140, -140, -140, -140,  147,\n     -140, -140, -140, -140, -140, -140, -140, -140, -140, -140,\n     -140, -140, -140, -140, -140, -140, -140, -140, -140, -140,\n     -140, -140, -140, -140, -140, -140, -140, -140, -140, -140,\n\n     -140,  147, -140, -140, -140, -140, -140, -140, -140, -140,\n     -140, -140, -140, -140, -140, -140, -140, -140, -140, -140,\n     -140, -140, -140, -140, -140, -140, -140, -140\n    },\n\n    {\n        5, -141, -141, -141, -141, -141, -141, -141, -141, -141,\n     -141, -141, -141, -141, -141, -141, -141, -141, -141, -141,\n     -141, -141, -141, -141, -141, -141, -141, -141, -141, -141,\n     -141, -141, -141, -141, -141, -141, -141, -141, -141, -141,\n     -141, -141, -141, -141, -141, -141, -141, -141, -141, -141,\n     -141, -141, -141, -141, -141, -141, -141, -141, -141, -141,\n     -141, -141, -141, -141, -141, -141, -141, -141, -141, -141,\n\n     -141, -141, -141, -141, -141, -141, -141, -141,  148, -141,\n     -141, -141, -141, -141, -141, -141, -141, -141, -141, -141,\n     -141, -141, -141, -141, -141, -141, -141, -141, -141, -141,\n     -141, -141, -141, -141, -141, -141, -141, -141, -141, -141,\n      148, -141, -141, -141, -141, -141, -141, -141, -141, -141,\n     -141, -141, -141, -141, -141, -141, -141, -141\n    },\n\n    {\n        5, -142, -142, -142, -142, -142, -142, -142, -142, -142,\n     -142, -142, -142, -142, -142, -142, -142, -142, -142, -142,\n     -142, -142, -142, -142, -142, -142, -142, -142, -142, -142,\n     -142, -142, -142, -142, -142, -142, -142, -142, -142, -142,\n\n     -142, -142, -142, -142, -142, -142, -142, -142, -142, -142,\n     -142, -142, -142, -142, -142, -142, -142, -142, -142, -142,\n     -142, -142, -142, -142, -142, -142, -142, -142, -142,  149,\n     -142, -142, -142, -142, -142, -142, -142, -142, -142, -142,\n     -142, -142, -142, -142, -142, -142, -142, -142, -142, -142,\n     -142, -142, -142, -142, -142, -142, -142, -142, -142, -142,\n     -142,  149, -142, -142, -142, -142, -142, -142, -142, -142,\n     -142, -142, -142, -142, -142, -142, -142, -142, -142, -142,\n     -142, -142, -142, -142, -142, -142, -142, -142\n    },\n\n    {\n        5, -143, -143, -143, -143, -143, -143, -143, -143, -143,\n\n     -143, -143, -143, -143, -143, -143, -143, -143, -143, -143,\n     -143, -143, -143, -143, -143, -143, -143, -143, -143, -143,\n     -143, -143, -143, -143, -143, -143, -143, -143, -143, -143,\n     -143, -143, -143, -143, -143, -143, -143, -143, -143, -143,\n     -143, -143, -143, -143, -143, -143, -143, -143, -143, -143,\n     -143, -143, -143, -143, -143, -143, -143, -143, -143, -143,\n     -143, -143, -143, -143, -143, -143, -143,  150, -143, -143,\n     -143, -143, -143, -143, -143, -143, -143, -143, -143, -143,\n     -143, -143, -143, -143, -143, -143, -143, -143, -143, -143,\n     -143, -143, -143, -143, -143, -143, -143, -143, -143,  150,\n\n     -143, -143, -143, -143, -143, -143, -143, -143, -143, -143,\n     -143, -143, -143, -143, -143, -143, -143, -143\n    },\n\n    {\n        5, -144, -144, -144, -144, -144, -144, -144, -144, -144,\n     -144, -144, -144, -144, -144, -144, -144, -144, -144, -144,\n     -144, -144, -144, -144, -144, -144, -144, -144, -144, -144,\n     -144, -144, -144, -144, -144, -144, -144, -144, -144, -144,\n     -144, -144, -144, -144, -144, -144, -144, -144, -144, -144,\n     -144, -144, -144, -144, -144, -144, -144, -144, -144, -144,\n     -144, -144, -144, -144, -144, -144, -144, -144, -144,  151,\n     -144, -144, -144, -144, -144, -144, -144, -144, -144, -144,\n\n     -144, -144, -144, -144, -144, -144, -144, -144, -144, -144,\n     -144, -144, -144, -144, -144, -144, -144, -144, -144, -144,\n     -144,  151, -144, -144, -144, -144, -144, -144, -144, -144,\n     -144, -144, -144, -144, -144, -144, -144, -144, -144, -144,\n     -144, -144, -144, -144, -144, -144, -144, -144\n    },\n\n    {\n        5, -145, -145, -145, -145, -145, -145, -145, -145, -145,\n     -145, -145, -145, -145, -145, -145, -145, -145, -145, -145,\n     -145, -145, -145, -145, -145, -145, -145, -145, -145, -145,\n     -145, -145, -145, -145, -145, -145, -145, -145, -145, -145,\n     -145, -145, -145, -145, -145, -145, -145, -145, -145, -145,\n\n     -145, -145, -145, -145, -145, -145, -145, -145, -145, -145,\n     -145, -145, -145, -145, -145, -145, -145, -145, -145, -145,\n     -145, -145, -145,  152, -145, -145, -145, -145, -145, -145,\n     -145, -145, -145, -145, -145, -145, -145, -145, -145, -145,\n     -145, -145, -145, -145, -145, -145, -145, -145, -145, -145,\n     -145, -145, -145, -145, -145,  152, -145, -145, -145, -145,\n     -145, -145, -145, -145, -145, -145, -145, -145, -145, -145,\n     -145, -145, -145, -145, -145, -145, -145, -145\n    },\n\n    {\n        5, -146, -146, -146, -146, -146, -146, -146, -146, -146,\n     -146, -146, -146, -146, -146, -146, -146, -146, -146, -146,\n\n     -146, -146, -146, -146, -146, -146, -146, -146, -146, -146,\n     -146, -146, -146, -146, -146, -146, -146, -146, -146, -146,\n     -146, -146, -146, -146, -146, -146, -146, -146, -146, -146,\n     -146, -146, -146, -146, -146, -146, -146, -146, -146, -146,\n     -146, -146, -146, -146, -146, -146, -146, -146, -146, -146,\n     -146, -146, -146, -146, -146, -146, -146,  153, -146, -146,\n     -146, -146, -146, -146, -146, -146, -146, -146, -146, -146,\n     -146, -146, -146, -146, -146, -146, -146, -146, -146, -146,\n     -146, -146, -146, -146, -146, -146, -146, -146, -146,  153,\n     -146, -146, -146, -146, -146, -146, -146, -146, -146, -146,\n\n     -146, -146, -146, -146, -146, -146, -146, -146\n    },\n\n    {\n        5, -147, -147, -147, -147, -147, -147, -147, -147, -147,\n     -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,\n     -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,\n     -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,\n     -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,\n     -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,\n     -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,\n     -147, -147, -147, -147, -147, -147, -147,  154, -147, -147,\n     -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,\n\n     -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,\n     -147, -147, -147, -147, -147, -147, -147, -147, -147,  154,\n     -147, -147, -147, -147, -147, -147, -147, -147, -147, -147,\n     -147, -147, -147, -147, -147, -147, -147, -147\n    },\n\n    {\n        5, -148, -148, -148, -148, -148, -148, -148, -148, -148,\n     -148, -148, -148, -148, -148, -148, -148, -148, -148, -148,\n     -148, -148, -148, -148, -148, -148, -148, -148, -148, -148,\n     -148, -148, -148, -148, -148, -148, -148, -148, -148, -148,\n     -148, -148, -148, -148, -148, -148, -148, -148, -148, -148,\n     -148, -148, -148, -148, -148, -148, -148, -148, -148, -148,\n\n     -148, -148, -148, -148, -148, -148, -148, -148, -148, -148,\n     -148,  155, -148, -148, -148, -148, -148, -148, -148, -148,\n     -148, -148, -148, -148, -148, -148, -148, -148, -148, -148,\n     -148, -148, -148, -148, -148, -148, -148, -148, -148, -148,\n     -148, -148, -148,  155, -148, -148, -148, -148, -148, -148,\n     -148, -148, -148, -148, -148, -148, -148, -148, -148, -148,\n     -148, -148, -148, -148, -148, -148, -148, -148\n    },\n\n    {\n        5, -149, -149, -149, -149, -149, -149, -149, -149, -149,\n     -149, -149, -149, -149, -149, -149, -149, -149, -149, -149,\n     -149, -149, -149, -149, -149, -149, -149, -149, -149, -149,\n\n     -149, -149, -149, -149, -149, -149, -149, -149, -149, -149,\n     -149, -149, -149, -149, -149, -149, -149, -149, -149, -149,\n     -149, -149, -149, -149, -149, -149, -149, -149, -149, -149,\n     -149, -149, -149, -149, -149, -149, -149, -149, -149, -149,\n     -149, -149, -149, -149, -149, -149, -149,  156, -149, -149,\n     -149, -149, -149, -149, -149, -149, -149, -149, -149, -149,\n     -149, -149, -149, -149, -149, -149, -149, -149, -149, -149,\n     -149, -149, -149, -149, -149, -149, -149, -149, -149,  156,\n     -149, -149, -149, -149, -149, -149, -149, -149, -149, -149,\n     -149, -149, -149, -149, -149, -149, -149, -149\n\n    },\n\n    {\n        5, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n     -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n     -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n     -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n     -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n     -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n     -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n     -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n     -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n     -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n\n     -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n     -150, -150, -150, -150, -150, -150, -150, -150, -150, -150,\n     -150, -150, -150, -150, -150, -150, -150, -150\n    },\n\n    {\n        5, -151, -151, -151, -151, -151, -151, -151, -151, -151,\n     -151, -151, -151, -151, -151, -151, -151, -151, -151, -151,\n     -151, -151, -151, -151, -151, -151, -151, -151, -151, -151,\n     -151, -151, -151, -151, -151, -151, -151, -151, -151, -151,\n     -151, -151, -151, -151, -151, -151, -151, -151, -151, -151,\n     -151, -151, -151, -151, -151, -151, -151, -151, -151, -151,\n     -151, -151, -151, -151, -151, -151, -151,  157, -151, -151,\n\n     -151, -151, -151, -151, -151, -151, -151, -151, -151, -151,\n     -151, -151, -151, -151, -151, -151, -151, -151, -151, -151,\n     -151, -151, -151, -151, -151, -151, -151, -151, -151,  157,\n     -151, -151, -151, -151, -151, -151, -151, -151, -151, -151,\n     -151, -151, -151, -151, -151, -151, -151, -151, -151, -151,\n     -151, -151, -151, -151, -151, -151, -151, -151\n    },\n\n    {\n        5, -152, -152, -152, -152, -152, -152, -152, -152, -152,\n     -152, -152, -152, -152, -152, -152, -152, -152, -152, -152,\n     -152, -152, -152, -152, -152, -152, -152, -152, -152, -152,\n     -152, -152, -152, -152, -152, -152, -152, -152, -152, -152,\n\n     -152, -152, -152, -152, -152, -152, -152, -152, -152, -152,\n     -152, -152, -152, -152, -152, -152, -152, -152, -152, -152,\n     -152, -152, -152, -152, -152, -152, -152, -152, -152, -152,\n     -152, -152, -152, -152, -152, -152, -152, -152,  158, -152,\n     -152, -152, -152, -152, -152, -152, -152, -152, -152, -152,\n     -152, -152, -152, -152, -152, -152, -152, -152, -152, -152,\n     -152, -152, -152, -152, -152, -152, -152, -152, -152, -152,\n      158, -152, -152, -152, -152, -152, -152, -152, -152, -152,\n     -152, -152, -152, -152, -152, -152, -152, -152\n    },\n\n    {\n        5, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n\n     -153, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n     -153, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n     -153, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n     -153, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n     -153, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n     -153, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n     -153, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n     -153, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n     -153, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n     -153, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n\n     -153, -153, -153, -153, -153, -153, -153, -153, -153, -153,\n     -153, -153, -153, -153, -153, -153, -153, -153\n    },\n\n    {\n        5, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n     -154, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n     -154, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n     -154, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n     -154, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n     -154, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n     -154, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n     -154, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n\n     -154, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n     -154, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n     -154, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n     -154, -154, -154, -154, -154, -154, -154, -154, -154, -154,\n     -154, -154, -154, -154, -154, -154, -154, -154\n    },\n\n    {\n        5, -155, -155, -155, -155, -155, -155, -155, -155, -155,\n     -155, -155, -155, -155, -155, -155, -155, -155, -155, -155,\n     -155, -155, -155, -155, -155, -155, -155, -155, -155, -155,\n     -155, -155, -155, -155, -155, -155, -155, -155, -155, -155,\n     -155, -155, -155, -155, -155, -155, -155, -155, -155, -155,\n\n     -155, -155, -155, -155, -155, -155, -155, -155, -155, -155,\n     -155, -155, -155, -155, -155, -155, -155, -155, -155, -155,\n     -155, -155, -155, -155, -155, -155, -155,  159, -155, -155,\n     -155, -155, -155, -155, -155, -155, -155, -155, -155, -155,\n     -155, -155, -155, -155, -155, -155, -155, -155, -155, -155,\n     -155, -155, -155, -155, -155, -155, -155, -155, -155,  159,\n     -155, -155, -155, -155, -155, -155, -155, -155, -155, -155,\n     -155, -155, -155, -155, -155, -155, -155, -155\n    },\n\n    {\n        5, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n     -156, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n\n     -156, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n     -156, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n     -156, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n     -156, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n     -156, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n     -156, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n     -156, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n     -156, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n     -156, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n     -156, -156, -156, -156, -156, -156, -156, -156, -156, -156,\n\n     -156, -156, -156, -156, -156, -156, -156, -156\n    },\n\n    {\n        5, -157, -157, -157, -157, -157, -157, -157, -157, -157,\n     -157, -157, -157, -157, -157, -157, -157, -157, -157, -157,\n     -157, -157, -157, -157, -157, -157, -157, -157, -157, -157,\n     -157, -157, -157, -157, -157, -157, -157, -157, -157, -157,\n     -157, -157, -157, -157, -157, -157, -157, -157, -157, -157,\n     -157, -157, -157, -157, -157, -157, -157, -157, -157, -157,\n     -157, -157, -157, -157, -157, -157, -157, -157, -157, -157,\n     -157, -157, -157, -157, -157, -157, -157, -157, -157, -157,\n     -157, -157, -157, -157,  160, -157, -157, -157, -157, -157,\n\n     -157, -157, -157, -157, -157, -157, -157, -157, -157, -157,\n     -157, -157, -157, -157, -157, -157, -157, -157, -157, -157,\n     -157, -157, -157, -157, -157, -157,  160, -157, -157, -157,\n     -157, -157, -157, -157, -157, -157, -157, -157\n    },\n\n    {\n        5, -158, -158, -158, -158, -158, -158, -158, -158, -158,\n     -158, -158, -158, -158, -158, -158, -158, -158, -158, -158,\n     -158, -158, -158, -158, -158, -158, -158, -158, -158, -158,\n     -158, -158, -158, -158, -158, -158, -158, -158, -158, -158,\n     -158, -158, -158, -158, -158, -158, -158, -158, -158, -158,\n     -158, -158, -158, -158, -158, -158, -158, -158, -158, -158,\n\n     -158, -158, -158, -158, -158, -158, -158, -158, -158, -158,\n     -158,  161, -158, -158, -158, -158, -158, -158, -158, -158,\n     -158, -158, -158, -158, -158, -158, -158, -158, -158, -158,\n     -158, -158, -158, -158, -158, -158, -158, -158, -158, -158,\n     -158, -158, -158,  161, -158, -158, -158, -158, -158, -158,\n     -158, -158, -158, -158, -158, -158, -158, -158, -158, -158,\n     -158, -158, -158, -158, -158, -158, -158, -158\n    },\n\n    {\n        5, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n     -159, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n     -159, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n\n     -159, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n     -159, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n     -159, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n     -159, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n     -159, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n     -159, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n     -159, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n     -159, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n     -159, -159, -159, -159, -159, -159, -159, -159, -159, -159,\n     -159, -159, -159, -159, -159, -159, -159, -159\n\n    },\n\n    {\n        5, -160, -160, -160, -160, -160, -160, -160, -160, -160,\n     -160, -160, -160, -160, -160, -160, -160, -160, -160, -160,\n     -160, -160, -160, -160, -160, -160, -160, -160, -160, -160,\n     -160, -160, -160, -160, -160, -160, -160, -160, -160, -160,\n     -160, -160, -160, -160, -160, -160, -160, -160, -160, -160,\n     -160, -160, -160, -160, -160, -160, -160, -160, -160, -160,\n     -160, -160, -160, -160, -160, -160, -160, -160, -160, -160,\n     -160, -160, -160,  162, -160, -160, -160, -160, -160, -160,\n     -160, -160, -160, -160, -160, -160, -160, -160, -160, -160,\n     -160, -160, -160, -160, -160, -160, -160, -160, -160, -160,\n\n     -160, -160, -160, -160, -160,  162, -160, -160, -160, -160,\n     -160, -160, -160, -160, -160, -160, -160, -160, -160, -160,\n     -160, -160, -160, -160, -160, -160, -160, -160\n    },\n\n    {\n        5, -161, -161, -161, -161, -161, -161, -161, -161, -161,\n     -161, -161, -161, -161, -161, -161, -161, -161, -161, -161,\n     -161, -161, -161, -161, -161, -161, -161, -161, -161, -161,\n     -161, -161, -161, -161, -161, -161, -161, -161, -161, -161,\n     -161, -161, -161, -161, -161, -161, -161, -161, -161, -161,\n     -161, -161, -161, -161, -161, -161, -161, -161, -161, -161,\n     -161, -161, -161, -161, -161, -161, -161, -161, -161, -161,\n\n     -161, -161, -161, -161, -161, -161, -161,  163, -161, -161,\n     -161, -161, -161, -161, -161, -161, -161, -161, -161, -161,\n     -161, -161, -161, -161, -161, -161, -161, -161, -161, -161,\n     -161, -161, -161, -161, -161, -161, -161, -161, -161,  163,\n     -161, -161, -161, -161, -161, -161, -161, -161, -161, -161,\n     -161, -161, -161, -161, -161, -161, -161, -161\n    },\n\n    {\n        5, -162, -162, -162, -162, -162, -162, -162, -162, -162,\n     -162, -162, -162, -162, -162, -162, -162, -162, -162, -162,\n     -162, -162, -162, -162, -162, -162, -162, -162, -162, -162,\n     -162, -162, -162, -162, -162, -162, -162, -162, -162, -162,\n\n     -162, -162, -162, -162, -162, -162, -162, -162, -162, -162,\n     -162, -162, -162, -162, -162, -162, -162, -162, -162, -162,\n     -162, -162, -162, -162, -162, -162, -162, -162, -162, -162,\n     -162, -162, -162, -162, -162, -162, -162, -162, -162,  164,\n     -162, -162, -162, -162, -162, -162, -162, -162, -162, -162,\n     -162, -162, -162, -162, -162, -162, -162, -162, -162, -162,\n     -162, -162, -162, -162, -162, -162, -162, -162, -162, -162,\n     -162,  164, -162, -162, -162, -162, -162, -162, -162, -162,\n     -162, -162, -162, -162, -162, -162, -162, -162\n    },\n\n    {\n        5, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n\n     -163, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n     -163, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n     -163, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n     -163, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n     -163, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n     -163, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n     -163, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n     -163, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n     -163, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n     -163, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n\n     -163, -163, -163, -163, -163, -163, -163, -163, -163, -163,\n     -163, -163, -163, -163, -163, -163, -163, -163\n    },\n\n    {\n        5, -164, -164, -164, -164, -164, -164, -164, -164, -164,\n     -164, -164, -164, -164, -164, -164, -164, -164, -164, -164,\n     -164, -164, -164, -164, -164, -164, -164, -164, -164, -164,\n     -164, -164, -164, -164, -164, -164, -164, -164, -164, -164,\n     -164, -164, -164, -164, -164, -164, -164, -164, -164, -164,\n     -164, -164, -164, -164, -164, -164, -164, -164, -164, -164,\n     -164, -164, -164, -164, -164, -164, -164, -164, -164, -164,\n     -164, -164, -164, -164, -164, -164, -164, -164,  165, -164,\n\n     -164, -164, -164, -164, -164, -164, -164, -164, -164, -164,\n     -164, -164, -164, -164, -164, -164, -164, -164, -164, -164,\n     -164, -164, -164, -164, -164, -164, -164, -164, -164, -164,\n      165, -164, -164, -164, -164, -164, -164, -164, -164, -164,\n     -164, -164, -164, -164, -164, -164, -164, -164\n    },\n\n    {\n        5, -165, -165, -165, -165, -165, -165, -165, -165, -165,\n     -165, -165, -165, -165, -165, -165, -165, -165, -165, -165,\n     -165, -165, -165, -165, -165, -165, -165, -165, -165, -165,\n     -165, -165, -165, -165, -165, -165, -165, -165, -165, -165,\n     -165, -165, -165, -165, -165, -165, -165, -165, -165, -165,\n\n     -165, -165, -165, -165, -165, -165, -165, -165, -165, -165,\n     -165, -165, -165, -165, -165, -165, -165, -165, -165, -165,\n     -165, -165, -165, -165, -165, -165, -165,  166, -165, -165,\n     -165, -165, -165, -165, -165, -165, -165, -165, -165, -165,\n     -165, -165, -165, -165, -165, -165, -165, -165, -165, -165,\n     -165, -165, -165, -165, -165, -165, -165, -165, -165,  166,\n     -165, -165, -165, -165, -165, -165, -165, -165, -165, -165,\n     -165, -165, -165, -165, -165, -165, -165, -165\n    },\n\n    {\n        5, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n     -166, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n\n     -166, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n     -166, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n     -166, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n     -166, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n     -166, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n     -166, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n     -166, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n     -166, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n     -166, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n     -166, -166, -166, -166, -166, -166, -166, -166, -166, -166,\n\n     -166, -166, -166, -166, -166, -166, -166, -166\n    },\n\n    } ;\n\nstatic yy_state_type yy_get_previous_state (void );\nstatic yy_state_type yy_try_NUL_trans (yy_state_type current_state  );\nstatic int yy_get_next_buffer (void );\nstatic void yy_fatal_error (yyconst char msg[]  );\n\n/* Done after the current pattern has been matched and before the\n * corresponding action - sets up lwg_parse_yytext.\n */\n#define YY_DO_BEFORE_ACTION \\\n\t(yytext_ptr) = yy_bp; \\\n\tlwg_parse_yyleng = (size_t) (yy_cp - yy_bp); \\\n\t(yy_hold_char) = *yy_cp; \\\n\t*yy_cp = '\\0'; \\\n\t(yy_c_buf_p) = yy_cp;\n\n#define YY_NUM_RULES 38\n#define YY_END_OF_BUFFER 39\n/* This struct is not used in this scanner,\n   but its presence is necessary. */\nstruct yy_trans_info\n\t{\n\tflex_int32_t yy_verify;\n\tflex_int32_t yy_nxt;\n\t};\nstatic yyconst flex_int16_t yy_accept[167] =\n    {   0,\n        0,    0,    0,    0,   39,   37,   36,   36,   31,   32,\n       33,   37,   35,   34,   37,   37,   37,   37,   37,   37,\n       37,   37,   37,    1,   36,    3,    4,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    1,    2,    0,\n        0,    3,    4,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    1,    0,    1,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,   29,    0,    2,    0,\n        0,    0,   30,    0,    0,    0,    5,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    6,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,   11,    0,\n\n        0,    0,    0,    0,    0,    0,    0,    0,    0,   12,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    7,   21,    0,   17,    0,    0,\n        0,    0,    0,    0,    8,   22,    0,   18,    0,    0,\n        0,    0,   15,    0,    0,   23,   25,    0,   13,   16,\n        0,    0,   24,   26,    9,   14,    0,    0,   10,    0,\n       19,    0,   20,    0,   27,   28\n    } ;\n\nstatic yy_state_type yy_last_accepting_state;\nstatic char *yy_last_accepting_cpos;\n\nstatic yyconst yy_state_type yy_NUL_trans[167] =\n    {   0,\n        6,    6,    6,    6,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0\n    } ;\n\nextern int lwg_parse_yy_flex_debug;\nint lwg_parse_yy_flex_debug = 0;\n\n/* The intent behind this definition is that it'll catch\n * any uses of REJECT which flex missed.\n */\n#define REJECT reject_used_but_not_detected\n#define yymore() yymore_used_but_not_detected\n#define YY_MORE_ADJ 0\n#define YY_RESTORE_YY_MORE_OFFSET\nchar *lwg_parse_yytext;\n#line 1 \"wktparse.lex\"\n/*\n * Written by Ralph Mason ralph.mason<at>telogis.com\n *\n * Copyright Telogis 2004\n * www.telogis.com\n *\n */\n\n#line 11 \"wktparse.lex\"\n#include \"wktparse.tab.h\"\n#include <unistd.h>\n#include <stdlib.h> /* need stdlib for atof() definition */\n\nvoid init_parser(const char *src);\nvoid close_parser(void);\nint lwg_parse_yywrap(void);\nint lwg_parse_yylex(void);\n\nstatic YY_BUFFER_STATE buf_state;\n   void init_parser(const char *src) { BEGIN(0);buf_state = lwg_parse_yy_scan_string(src); }\n   void close_parser() { lwg_parse_yy_delete_buffer(buf_state); }\n   int lwg_parse_yywrap(void){ return 1; }\n\n/* Macro to keep track of the current parse position */\n#define UPDATE_YYLLOC() (lwg_parse_yylloc.last_column += lwg_parse_yyleng)\n\n#line 3370 \"lex.yy.c\"\n\n#define INITIAL 0\n#define vals_ok 1\n\n#ifndef YY_NO_UNISTD_H\n/* Special case for \"unistd.h\", since it is non-ANSI. We include it way\n * down here because we want the user's section 1 to have been scanned first.\n * The user has a chance to override it with an option.\n */\n#include <unistd.h>\n#endif\n\n#ifndef YY_EXTRA_TYPE\n#define YY_EXTRA_TYPE void *\n#endif\n\nstatic int yy_init_globals (void );\n\n/* Accessor methods to globals.\n   These are made visible to non-reentrant scanners for convenience. */\n\nint lwg_parse_yylex_destroy (void );\n\nint lwg_parse_yyget_debug (void );\n\nvoid lwg_parse_yyset_debug (int debug_flag  );\n\nYY_EXTRA_TYPE lwg_parse_yyget_extra (void );\n\nvoid lwg_parse_yyset_extra (YY_EXTRA_TYPE user_defined  );\n\nFILE *lwg_parse_yyget_in (void );\n\nvoid lwg_parse_yyset_in  (FILE * in_str  );\n\nFILE *lwg_parse_yyget_out (void );\n\nvoid lwg_parse_yyset_out  (FILE * out_str  );\n\nint lwg_parse_yyget_leng (void );\n\nchar *lwg_parse_yyget_text (void );\n\nint lwg_parse_yyget_lineno (void );\n\nvoid lwg_parse_yyset_lineno (int line_number  );\n\n/* Macros after this point can all be overridden by user definitions in\n * section 1.\n */\n\n#ifndef YY_SKIP_YYWRAP\n#ifdef __cplusplus\nextern \"C\" int lwg_parse_yywrap (void );\n#else\nextern int lwg_parse_yywrap (void );\n#endif\n#endif\n\n    static void yyunput (int c,char *buf_ptr  );\n    \n#ifndef yytext_ptr\nstatic void yy_flex_strncpy (char *,yyconst char *,int );\n#endif\n\n#ifdef YY_NEED_STRLEN\nstatic int yy_flex_strlen (yyconst char * );\n#endif\n\n#ifndef YY_NO_INPUT\n\n#ifdef __cplusplus\nstatic int yyinput (void );\n#else\nstatic int input (void );\n#endif\n\n#endif\n\n/* Amount of stuff to slurp up with each read. */\n#ifndef YY_READ_BUF_SIZE\n#define YY_READ_BUF_SIZE 8192\n#endif\n\n/* Copy whatever the last rule matched to the standard output. */\n#ifndef ECHO\n/* This used to be an fputs(), but since the string might contain NUL's,\n * we now use fwrite().\n */\n#define ECHO fwrite( lwg_parse_yytext, lwg_parse_yyleng, 1, lwg_parse_yyout )\n#endif\n\n/* Gets input and stuffs it into \"buf\".  number of characters read, or YY_NULL,\n * is returned in \"result\".\n */\n#ifndef YY_INPUT\n#define YY_INPUT(buf,result,max_size) \\\n\terrno=0; \\\n\twhile ( (result = read( fileno(lwg_parse_yyin), (char *) buf, max_size )) < 0 ) \\\n\t{ \\\n\t\tif( errno != EINTR) \\\n\t\t{ \\\n\t\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" ); \\\n\t\t\tbreak; \\\n\t\t} \\\n\t\terrno=0; \\\n\t\tclearerr(lwg_parse_yyin); \\\n\t}\\\n\\\n\n#endif\n\n/* No semi-colon after return; correct usage is to write \"yyterminate();\" -\n * we don't want an extra ';' after the \"return\" because that will cause\n * some compilers to complain about unreachable statements.\n */\n#ifndef yyterminate\n#define yyterminate() return YY_NULL\n#endif\n\n/* Number of entries by which start-condition stack grows. */\n#ifndef YY_START_STACK_INCR\n#define YY_START_STACK_INCR 25\n#endif\n\n/* Report a fatal error. */\n#ifndef YY_FATAL_ERROR\n#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )\n#endif\n\n/* end tables serialization structures and prototypes */\n\n/* Default declaration of generated scanner - a define so the user can\n * easily add parameters.\n */\n#ifndef YY_DECL\n#define YY_DECL_IS_OURS 1\n\nextern int lwg_parse_yylex (void);\n\n#define YY_DECL int lwg_parse_yylex (void)\n#endif /* !YY_DECL */\n\n/* Code executed at the beginning of each rule, after lwg_parse_yytext and lwg_parse_yyleng\n * have been set up.\n */\n#ifndef YY_USER_ACTION\n#define YY_USER_ACTION\n#endif\n\n/* Code executed at the end of each rule. */\n#ifndef YY_BREAK\n#define YY_BREAK break;\n#endif\n\n#define YY_RULE_SETUP \\\n\tYY_USER_ACTION\n\n/** The main scanner function which does all the work.\n */\nYY_DECL\n{\n\tregister yy_state_type yy_current_state;\n\tregister char *yy_cp, *yy_bp;\n\tregister int yy_act;\n    \n#line 30 \"wktparse.lex\"\n\n\n#line 3540 \"lex.yy.c\"\n\n\tif ( !(yy_init) )\n\t\t{\n\t\t(yy_init) = 1;\n\n#ifdef YY_USER_INIT\n\t\tYY_USER_INIT;\n#endif\n\n\t\tif ( ! (yy_start) )\n\t\t\t(yy_start) = 1;\t/* first start state */\n\n\t\tif ( ! lwg_parse_yyin )\n\t\t\tlwg_parse_yyin = stdin;\n\n\t\tif ( ! lwg_parse_yyout )\n\t\t\tlwg_parse_yyout = stdout;\n\n\t\tif ( ! YY_CURRENT_BUFFER ) {\n\t\t\tlwg_parse_yyensure_buffer_stack ();\n\t\t\tYY_CURRENT_BUFFER_LVALUE =\n\t\t\t\tlwg_parse_yy_create_buffer(lwg_parse_yyin,YY_BUF_SIZE );\n\t\t}\n\n\t\tlwg_parse_yy_load_buffer_state( );\n\t\t}\n\n\twhile ( 1 )\t\t/* loops until end-of-file is reached */\n\t\t{\n\t\tyy_cp = (yy_c_buf_p);\n\n\t\t/* Support of lwg_parse_yytext. */\n\t\t*yy_cp = (yy_hold_char);\n\n\t\t/* yy_bp points to the position in yy_ch_buf of the start of\n\t\t * the current run.\n\t\t */\n\t\tyy_bp = yy_cp;\n\n\t\tyy_current_state = (yy_start);\nyy_match:\n\t\twhile ( (yy_current_state = yy_nxt[yy_current_state][ YY_SC_TO_UI(*yy_cp) ]) > 0 )\n\t\t\t{\n\t\t\tif ( yy_accept[yy_current_state] )\n\t\t\t\t{\n\t\t\t\t(yy_last_accepting_state) = yy_current_state;\n\t\t\t\t(yy_last_accepting_cpos) = yy_cp;\n\t\t\t\t}\n\n\t\t\t++yy_cp;\n\t\t\t}\n\n\t\tyy_current_state = -yy_current_state;\n\nyy_find_action:\n\t\tyy_act = yy_accept[yy_current_state];\n\n\t\tYY_DO_BEFORE_ACTION;\n\ndo_action:\t/* This label is used only to access EOF actions. */\n\n\t\tswitch ( yy_act )\n\t{ /* beginning of action switch */\n\t\t\tcase 0: /* must back up */\n\t\t\t/* undo the effects of YY_DO_BEFORE_ACTION */\n\t\t\t*yy_cp = (yy_hold_char);\n\t\t\tyy_cp = (yy_last_accepting_cpos) + 1;\n\t\t\tyy_current_state = (yy_last_accepting_state);\n\t\t\tgoto yy_find_action;\n\ncase 1:\nYY_RULE_SETUP\n#line 32 \"wktparse.lex\"\n{ lwg_parse_yylval.value=atof(lwg_parse_yytext); UPDATE_YYLLOC(); return VALUE; }\n\tYY_BREAK\ncase 2:\nYY_RULE_SETUP\n#line 33 \"wktparse.lex\"\n{ lwg_parse_yylval.value=atof(lwg_parse_yytext); UPDATE_YYLLOC(); return VALUE; }\n\tYY_BREAK\ncase 3:\nYY_RULE_SETUP\n#line 35 \"wktparse.lex\"\n{  lwg_parse_yylval.wkb=lwg_parse_yytext; return WKB;}\n\tYY_BREAK\ncase 4:\nYY_RULE_SETUP\n#line 36 \"wktparse.lex\"\n{  lwg_parse_yylval.wkb=lwg_parse_yytext; return WKB;}\n\tYY_BREAK\ncase 5:\nYY_RULE_SETUP\n#line 38 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return POINT; }\n\tYY_BREAK\ncase 6:\nYY_RULE_SETUP\n#line 39 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return POINTM; }\n\tYY_BREAK\ncase 7:\nYY_RULE_SETUP\n#line 40 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return LINESTRING; }\n\tYY_BREAK\ncase 8:\nYY_RULE_SETUP\n#line 41 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return LINESTRINGM; }\n\tYY_BREAK\ncase 9:\nYY_RULE_SETUP\n#line 42 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return CIRCULARSTRING; }\n\tYY_BREAK\ncase 10:\nYY_RULE_SETUP\n#line 43 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return CIRCULARSTRINGM; }\n\tYY_BREAK\ncase 11:\nYY_RULE_SETUP\n#line 44 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return POLYGON; }\n\tYY_BREAK\ncase 12:\nYY_RULE_SETUP\n#line 45 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return POLYGONM; }\n\tYY_BREAK\ncase 13:\nYY_RULE_SETUP\n#line 46 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return COMPOUNDCURVE; }\n\tYY_BREAK\ncase 14:\nYY_RULE_SETUP\n#line 47 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return COMPOUNDCURVEM; }\n\tYY_BREAK\ncase 15:\nYY_RULE_SETUP\n#line 48 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return CURVEPOLYGON; }\n\tYY_BREAK\ncase 16:\nYY_RULE_SETUP\n#line 49 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return CURVEPOLYGONM; }\n\tYY_BREAK\ncase 17:\nYY_RULE_SETUP\n#line 50 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return MULTIPOINT; }\n\tYY_BREAK\ncase 18:\nYY_RULE_SETUP\n#line 51 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return MULTIPOINTM; }\n\tYY_BREAK\ncase 19:\nYY_RULE_SETUP\n#line 52 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return MULTILINESTRING; }\n\tYY_BREAK\ncase 20:\nYY_RULE_SETUP\n#line 53 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return MULTILINESTRINGM; }\n\tYY_BREAK\ncase 21:\nYY_RULE_SETUP\n#line 54 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return MULTICURVE; }\n\tYY_BREAK\ncase 22:\nYY_RULE_SETUP\n#line 55 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return MULTICURVEM; }\n\tYY_BREAK\ncase 23:\nYY_RULE_SETUP\n#line 56 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return MULTIPOLYGON; }\n\tYY_BREAK\ncase 24:\nYY_RULE_SETUP\n#line 57 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return MULTIPOLYGONM; }\n\tYY_BREAK\ncase 25:\nYY_RULE_SETUP\n#line 58 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return MULTISURFACE; }\n\tYY_BREAK\ncase 26:\nYY_RULE_SETUP\n#line 59 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return MULTISURFACEM; }\n\tYY_BREAK\ncase 27:\nYY_RULE_SETUP\n#line 60 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return GEOMETRYCOLLECTION; }\n\tYY_BREAK\ncase 28:\nYY_RULE_SETUP\n#line 61 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return GEOMETRYCOLLECTIONM; }\n\tYY_BREAK\ncase 29:\nYY_RULE_SETUP\n#line 62 \"wktparse.lex\"\n{ BEGIN(vals_ok); UPDATE_YYLLOC(); return SRID; }\n\tYY_BREAK\ncase 30:\nYY_RULE_SETUP\n#line 63 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return EMPTY; }\n\tYY_BREAK\ncase 31:\nYY_RULE_SETUP\n#line 65 \"wktparse.lex\"\n{ BEGIN(vals_ok); UPDATE_YYLLOC(); return LPAREN; }\n\tYY_BREAK\ncase 32:\nYY_RULE_SETUP\n#line 66 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return RPAREN; }\n\tYY_BREAK\ncase 33:\nYY_RULE_SETUP\n#line 67 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return COMMA ; }\n\tYY_BREAK\ncase 34:\nYY_RULE_SETUP\n#line 68 \"wktparse.lex\"\n{ UPDATE_YYLLOC(); return EQUALS ; }\n\tYY_BREAK\ncase 35:\nYY_RULE_SETUP\n#line 69 \"wktparse.lex\"\n{ BEGIN(0); UPDATE_YYLLOC(); return SEMICOLON; }\n\tYY_BREAK\ncase 36:\n/* rule 36 can match eol */\nYY_RULE_SETUP\n#line 70 \"wktparse.lex\"\n/*eat whitespace*/ { UPDATE_YYLLOC(); }\n\tYY_BREAK\ncase 37:\nYY_RULE_SETUP\n#line 71 \"wktparse.lex\"\n{ return lwg_parse_yytext[0]; }\n\tYY_BREAK\ncase 38:\nYY_RULE_SETUP\n#line 73 \"wktparse.lex\"\nECHO;\n\tYY_BREAK\n#line 3802 \"lex.yy.c\"\ncase YY_STATE_EOF(INITIAL):\ncase YY_STATE_EOF(vals_ok):\n\tyyterminate();\n\n\tcase YY_END_OF_BUFFER:\n\t\t{\n\t\t/* Amount of text matched not including the EOB char. */\n\t\tint yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;\n\n\t\t/* Undo the effects of YY_DO_BEFORE_ACTION. */\n\t\t*yy_cp = (yy_hold_char);\n\t\tYY_RESTORE_YY_MORE_OFFSET\n\n\t\tif ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )\n\t\t\t{\n\t\t\t/* We're scanning a new file or input source.  It's\n\t\t\t * possible that this happened because the user\n\t\t\t * just pointed lwg_parse_yyin at a new source and called\n\t\t\t * lwg_parse_yylex().  If so, then we have to assure\n\t\t\t * consistency between YY_CURRENT_BUFFER and our\n\t\t\t * globals.  Here is the right place to do so, because\n\t\t\t * this is the first action (other than possibly a\n\t\t\t * back-up) that will match for the new input source.\n\t\t\t */\n\t\t\t(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;\n\t\t\tYY_CURRENT_BUFFER_LVALUE->yy_input_file = lwg_parse_yyin;\n\t\t\tYY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;\n\t\t\t}\n\n\t\t/* Note that here we test for yy_c_buf_p \"<=\" to the position\n\t\t * of the first EOB in the buffer, since yy_c_buf_p will\n\t\t * already have been incremented past the NUL character\n\t\t * (since all states make transitions on EOB to the\n\t\t * end-of-buffer state).  Contrast this with the test\n\t\t * in input().\n\t\t */\n\t\tif ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )\n\t\t\t{ /* This was really a NUL. */\n\t\t\tyy_state_type yy_next_state;\n\n\t\t\t(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;\n\n\t\t\tyy_current_state = yy_get_previous_state(  );\n\n\t\t\t/* Okay, we're now positioned to make the NUL\n\t\t\t * transition.  We couldn't have\n\t\t\t * yy_get_previous_state() go ahead and do it\n\t\t\t * for us because it doesn't know how to deal\n\t\t\t * with the possibility of jamming (and we don't\n\t\t\t * want to build jamming into it because then it\n\t\t\t * will run more slowly).\n\t\t\t */\n\n\t\t\tyy_next_state = yy_try_NUL_trans( yy_current_state );\n\n\t\t\tyy_bp = (yytext_ptr) + YY_MORE_ADJ;\n\n\t\t\tif ( yy_next_state )\n\t\t\t\t{\n\t\t\t\t/* Consume the NUL. */\n\t\t\t\tyy_cp = ++(yy_c_buf_p);\n\t\t\t\tyy_current_state = yy_next_state;\n\t\t\t\tgoto yy_match;\n\t\t\t\t}\n\n\t\t\telse\n\t\t\t\t{\n\t\t\t\tyy_cp = (yy_c_buf_p);\n\t\t\t\tgoto yy_find_action;\n\t\t\t\t}\n\t\t\t}\n\n\t\telse switch ( yy_get_next_buffer(  ) )\n\t\t\t{\n\t\t\tcase EOB_ACT_END_OF_FILE:\n\t\t\t\t{\n\t\t\t\t(yy_did_buffer_switch_on_eof) = 0;\n\n\t\t\t\tif ( lwg_parse_yywrap( ) )\n\t\t\t\t\t{\n\t\t\t\t\t/* Note: because we've taken care in\n\t\t\t\t\t * yy_get_next_buffer() to have set up\n\t\t\t\t\t * lwg_parse_yytext, we can now set up\n\t\t\t\t\t * yy_c_buf_p so that if some total\n\t\t\t\t\t * hoser (like flex itself) wants to\n\t\t\t\t\t * call the scanner after we return the\n\t\t\t\t\t * YY_NULL, it'll still work - another\n\t\t\t\t\t * YY_NULL will get returned.\n\t\t\t\t\t */\n\t\t\t\t\t(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;\n\n\t\t\t\t\tyy_act = YY_STATE_EOF(YY_START);\n\t\t\t\t\tgoto do_action;\n\t\t\t\t\t}\n\n\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\tif ( ! (yy_did_buffer_switch_on_eof) )\n\t\t\t\t\t\tYY_NEW_FILE;\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\tcase EOB_ACT_CONTINUE_SCAN:\n\t\t\t\t(yy_c_buf_p) =\n\t\t\t\t\t(yytext_ptr) + yy_amount_of_matched_text;\n\n\t\t\t\tyy_current_state = yy_get_previous_state(  );\n\n\t\t\t\tyy_cp = (yy_c_buf_p);\n\t\t\t\tyy_bp = (yytext_ptr) + YY_MORE_ADJ;\n\t\t\t\tgoto yy_match;\n\n\t\t\tcase EOB_ACT_LAST_MATCH:\n\t\t\t\t(yy_c_buf_p) =\n\t\t\t\t&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];\n\n\t\t\t\tyy_current_state = yy_get_previous_state(  );\n\n\t\t\t\tyy_cp = (yy_c_buf_p);\n\t\t\t\tyy_bp = (yytext_ptr) + YY_MORE_ADJ;\n\t\t\t\tgoto yy_find_action;\n\t\t\t}\n\t\tbreak;\n\t\t}\n\n\tdefault:\n\t\tYY_FATAL_ERROR(\n\t\t\t\"fatal flex scanner internal error--no action found\" );\n\t} /* end of action switch */\n\t\t} /* end of scanning one token */\n} /* end of lwg_parse_yylex */\n\n/* yy_get_next_buffer - try to read in a new buffer\n *\n * Returns a code representing an action:\n *\tEOB_ACT_LAST_MATCH -\n *\tEOB_ACT_CONTINUE_SCAN - continue scanning from current position\n *\tEOB_ACT_END_OF_FILE - end of file\n */\nstatic int yy_get_next_buffer (void)\n{\n    \tregister char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;\n\tregister char *source = (yytext_ptr);\n\tregister int number_to_move, i;\n\tint ret_val;\n\n\tif ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )\n\t\tYY_FATAL_ERROR(\n\t\t\"fatal flex scanner internal error--end of buffer missed\" );\n\n\tif ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )\n\t\t{ /* Don't try to fill the buffer, so this is an EOF. */\n\t\tif ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )\n\t\t\t{\n\t\t\t/* We matched a single character, the EOB, so\n\t\t\t * treat this as a final EOF.\n\t\t\t */\n\t\t\treturn EOB_ACT_END_OF_FILE;\n\t\t\t}\n\n\t\telse\n\t\t\t{\n\t\t\t/* We matched some text prior to the EOB, first\n\t\t\t * process it.\n\t\t\t */\n\t\t\treturn EOB_ACT_LAST_MATCH;\n\t\t\t}\n\t\t}\n\n\t/* Try to read more data. */\n\n\t/* First move last chars to start of buffer. */\n\tnumber_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;\n\n\tfor ( i = 0; i < number_to_move; ++i )\n\t\t*(dest++) = *(source++);\n\n\tif ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )\n\t\t/* don't do the read, it's not guaranteed to return an EOF,\n\t\t * just force an EOF\n\t\t */\n\t\tYY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;\n\n\telse\n\t\t{\n\t\t\tint num_to_read =\n\t\t\tYY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;\n\n\t\twhile ( num_to_read <= 0 )\n\t\t\t{ /* Not enough room in the buffer - grow it. */\n\n\t\t\t/* just a shorter name for the current buffer */\n\t\t\tYY_BUFFER_STATE b = YY_CURRENT_BUFFER;\n\n\t\t\tint yy_c_buf_p_offset =\n\t\t\t\t(int) ((yy_c_buf_p) - b->yy_ch_buf);\n\n\t\t\tif ( b->yy_is_our_buffer )\n\t\t\t\t{\n\t\t\t\tint new_size = b->yy_buf_size * 2;\n\n\t\t\t\tif ( new_size <= 0 )\n\t\t\t\t\tb->yy_buf_size += b->yy_buf_size / 8;\n\t\t\t\telse\n\t\t\t\t\tb->yy_buf_size *= 2;\n\n\t\t\t\tb->yy_ch_buf = (char *)\n\t\t\t\t\t/* Include room in for 2 EOB chars. */\n\t\t\t\t\tlwg_parse_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t/* Can't grow it, we don't own it. */\n\t\t\t\tb->yy_ch_buf = 0;\n\n\t\t\tif ( ! b->yy_ch_buf )\n\t\t\t\tYY_FATAL_ERROR(\n\t\t\t\t\"fatal error - scanner input buffer overflow\" );\n\n\t\t\t(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];\n\n\t\t\tnum_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -\n\t\t\t\t\t\tnumber_to_move - 1;\n\n\t\t\t}\n\n\t\tif ( num_to_read > YY_READ_BUF_SIZE )\n\t\t\tnum_to_read = YY_READ_BUF_SIZE;\n\n\t\t/* Read in more data. */\n\t\tYY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),\n\t\t\t(yy_n_chars), (size_t) num_to_read );\n\n\t\tYY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);\n\t\t}\n\n\tif ( (yy_n_chars) == 0 )\n\t\t{\n\t\tif ( number_to_move == YY_MORE_ADJ )\n\t\t\t{\n\t\t\tret_val = EOB_ACT_END_OF_FILE;\n\t\t\tlwg_parse_yyrestart(lwg_parse_yyin  );\n\t\t\t}\n\n\t\telse\n\t\t\t{\n\t\t\tret_val = EOB_ACT_LAST_MATCH;\n\t\t\tYY_CURRENT_BUFFER_LVALUE->yy_buffer_status =\n\t\t\t\tYY_BUFFER_EOF_PENDING;\n\t\t\t}\n\t\t}\n\n\telse\n\t\tret_val = EOB_ACT_CONTINUE_SCAN;\n\n\tif ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {\n\t\t/* Extend the array by 50%, plus the number we really need. */\n\t\tyy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);\n\t\tYY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) lwg_parse_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );\n\t\tif ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )\n\t\t\tYY_FATAL_ERROR( \"out of dynamic memory in yy_get_next_buffer()\" );\n\t}\n\n\t(yy_n_chars) += number_to_move;\n\tYY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;\n\tYY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;\n\n\t(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];\n\n\treturn ret_val;\n}\n\n/* yy_get_previous_state - get the state just before the EOB char was reached */\n\n    static yy_state_type yy_get_previous_state (void)\n{\n\tregister yy_state_type yy_current_state;\n\tregister char *yy_cp;\n    \n\tyy_current_state = (yy_start);\n\n\tfor ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )\n\t\t{\n\t\tif ( *yy_cp )\n\t\t\t{\n\t\t\tyy_current_state = yy_nxt[yy_current_state][YY_SC_TO_UI(*yy_cp)];\n\t\t\t}\n\t\telse\n\t\t\tyy_current_state = yy_NUL_trans[yy_current_state];\n\t\tif ( yy_accept[yy_current_state] )\n\t\t\t{\n\t\t\t(yy_last_accepting_state) = yy_current_state;\n\t\t\t(yy_last_accepting_cpos) = yy_cp;\n\t\t\t}\n\t\t}\n\n\treturn yy_current_state;\n}\n\n/* yy_try_NUL_trans - try to make a transition on the NUL character\n *\n * synopsis\n *\tnext_state = yy_try_NUL_trans( current_state );\n */\n    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )\n{\n\tregister int yy_is_jam;\n    \tregister char *yy_cp = (yy_c_buf_p);\n\n\tyy_current_state = yy_NUL_trans[yy_current_state];\n\tyy_is_jam = (yy_current_state == 0);\n\n\tif ( ! yy_is_jam )\n\t\t{\n\t\tif ( yy_accept[yy_current_state] )\n\t\t\t{\n\t\t\t(yy_last_accepting_state) = yy_current_state;\n\t\t\t(yy_last_accepting_cpos) = yy_cp;\n\t\t\t}\n\t\t}\n\n\treturn yy_is_jam ? 0 : yy_current_state;\n}\n\n    static void yyunput (int c, register char * yy_bp )\n{\n\tregister char *yy_cp;\n    \n    yy_cp = (yy_c_buf_p);\n\n\t/* undo effects of setting up lwg_parse_yytext */\n\t*yy_cp = (yy_hold_char);\n\n\tif ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )\n\t\t{ /* need to shift things up to make room */\n\t\t/* +2 for EOB chars. */\n\t\tregister int number_to_move = (yy_n_chars) + 2;\n\t\tregister char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[\n\t\t\t\t\tYY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];\n\t\tregister char *source =\n\t\t\t\t&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];\n\n\t\twhile ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )\n\t\t\t*--dest = *--source;\n\n\t\tyy_cp += (int) (dest - source);\n\t\tyy_bp += (int) (dest - source);\n\t\tYY_CURRENT_BUFFER_LVALUE->yy_n_chars =\n\t\t\t(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;\n\n\t\tif ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )\n\t\t\tYY_FATAL_ERROR( \"flex scanner push-back overflow\" );\n\t\t}\n\n\t*--yy_cp = (char) c;\n\n\t(yytext_ptr) = yy_bp;\n\t(yy_hold_char) = *yy_cp;\n\t(yy_c_buf_p) = yy_cp;\n}\n\n#ifndef YY_NO_INPUT\n#ifdef __cplusplus\n    static int yyinput (void)\n#else\n    static int input  (void)\n#endif\n\n{\n\tint c;\n    \n\t*(yy_c_buf_p) = (yy_hold_char);\n\n\tif ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )\n\t\t{\n\t\t/* yy_c_buf_p now points to the character we want to return.\n\t\t * If this occurs *before* the EOB characters, then it's a\n\t\t * valid NUL; if not, then we've hit the end of the buffer.\n\t\t */\n\t\tif ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )\n\t\t\t/* This was really a NUL. */\n\t\t\t*(yy_c_buf_p) = '\\0';\n\n\t\telse\n\t\t\t{ /* need more input */\n\t\t\tint offset = (yy_c_buf_p) - (yytext_ptr);\n\t\t\t++(yy_c_buf_p);\n\n\t\t\tswitch ( yy_get_next_buffer(  ) )\n\t\t\t\t{\n\t\t\t\tcase EOB_ACT_LAST_MATCH:\n\t\t\t\t\t/* This happens because yy_g_n_b()\n\t\t\t\t\t * sees that we've accumulated a\n\t\t\t\t\t * token and flags that we need to\n\t\t\t\t\t * try matching the token before\n\t\t\t\t\t * proceeding.  But for input(),\n\t\t\t\t\t * there's no matching to consider.\n\t\t\t\t\t * So convert the EOB_ACT_LAST_MATCH\n\t\t\t\t\t * to EOB_ACT_END_OF_FILE.\n\t\t\t\t\t */\n\n\t\t\t\t\t/* Reset buffer status. */\n\t\t\t\t\tlwg_parse_yyrestart(lwg_parse_yyin );\n\n\t\t\t\t\t/*FALLTHROUGH*/\n\n\t\t\t\tcase EOB_ACT_END_OF_FILE:\n\t\t\t\t\t{\n\t\t\t\t\tif ( lwg_parse_yywrap( ) )\n\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\tif ( ! (yy_did_buffer_switch_on_eof) )\n\t\t\t\t\t\tYY_NEW_FILE;\n#ifdef __cplusplus\n\t\t\t\t\treturn yyinput();\n#else\n\t\t\t\t\treturn input();\n#endif\n\t\t\t\t\t}\n\n\t\t\t\tcase EOB_ACT_CONTINUE_SCAN:\n\t\t\t\t\t(yy_c_buf_p) = (yytext_ptr) + offset;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tc = *(unsigned char *) (yy_c_buf_p);\t/* cast for 8-bit char's */\n\t*(yy_c_buf_p) = '\\0';\t/* preserve lwg_parse_yytext */\n\t(yy_hold_char) = *++(yy_c_buf_p);\n\n\treturn c;\n}\n#endif\t/* ifndef YY_NO_INPUT */\n\n/** Immediately switch to a different input stream.\n * @param input_file A readable stream.\n * \n * @note This function does not reset the start condition to @c INITIAL .\n */\n    void lwg_parse_yyrestart  (FILE * input_file )\n{\n    \n\tif ( ! YY_CURRENT_BUFFER ){\n        lwg_parse_yyensure_buffer_stack ();\n\t\tYY_CURRENT_BUFFER_LVALUE =\n            lwg_parse_yy_create_buffer(lwg_parse_yyin,YY_BUF_SIZE );\n\t}\n\n\tlwg_parse_yy_init_buffer(YY_CURRENT_BUFFER,input_file );\n\tlwg_parse_yy_load_buffer_state( );\n}\n\n/** Switch to a different input buffer.\n * @param new_buffer The new input buffer.\n * \n */\n    void lwg_parse_yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )\n{\n    \n\t/* TODO. We should be able to replace this entire function body\n\t * with\n\t *\t\tlwg_parse_yypop_buffer_state();\n\t *\t\tlwg_parse_yypush_buffer_state(new_buffer);\n     */\n\tlwg_parse_yyensure_buffer_stack ();\n\tif ( YY_CURRENT_BUFFER == new_buffer )\n\t\treturn;\n\n\tif ( YY_CURRENT_BUFFER )\n\t\t{\n\t\t/* Flush out information for old buffer. */\n\t\t*(yy_c_buf_p) = (yy_hold_char);\n\t\tYY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);\n\t\tYY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);\n\t\t}\n\n\tYY_CURRENT_BUFFER_LVALUE = new_buffer;\n\tlwg_parse_yy_load_buffer_state( );\n\n\t/* We don't actually know whether we did this switch during\n\t * EOF (lwg_parse_yywrap()) processing, but the only time this flag\n\t * is looked at is after lwg_parse_yywrap() is called, so it's safe\n\t * to go ahead and always set it.\n\t */\n\t(yy_did_buffer_switch_on_eof) = 1;\n}\n\nstatic void lwg_parse_yy_load_buffer_state  (void)\n{\n    \t(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;\n\t(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;\n\tlwg_parse_yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;\n\t(yy_hold_char) = *(yy_c_buf_p);\n}\n\n/** Allocate and initialize an input buffer state.\n * @param file A readable stream.\n * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.\n * \n * @return the allocated buffer state.\n */\n    YY_BUFFER_STATE lwg_parse_yy_create_buffer  (FILE * file, int  size )\n{\n\tYY_BUFFER_STATE b;\n    \n\tb = (YY_BUFFER_STATE) lwg_parse_yyalloc(sizeof( struct yy_buffer_state )  );\n\tif ( ! b )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in lwg_parse_yy_create_buffer()\" );\n\n\tb->yy_buf_size = size;\n\n\t/* yy_ch_buf has to be 2 characters longer than the size given because\n\t * we need to put in 2 end-of-buffer characters.\n\t */\n\tb->yy_ch_buf = (char *) lwg_parse_yyalloc(b->yy_buf_size + 2  );\n\tif ( ! b->yy_ch_buf )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in lwg_parse_yy_create_buffer()\" );\n\n\tb->yy_is_our_buffer = 1;\n\n\tlwg_parse_yy_init_buffer(b,file );\n\n\treturn b;\n}\n\n/** Destroy the buffer.\n * @param b a buffer created with lwg_parse_yy_create_buffer()\n * \n */\n    void lwg_parse_yy_delete_buffer (YY_BUFFER_STATE  b )\n{\n    \n\tif ( ! b )\n\t\treturn;\n\n\tif ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */\n\t\tYY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;\n\n\tif ( b->yy_is_our_buffer )\n\t\tlwg_parse_yyfree((void *) b->yy_ch_buf  );\n\n\tlwg_parse_yyfree((void *) b  );\n}\n\n#ifndef __cplusplus\nextern int isatty (int );\n#endif /* __cplusplus */\n    \n/* Initializes or reinitializes a buffer.\n * This function is sometimes called more than once on the same buffer,\n * such as during a lwg_parse_yyrestart() or at EOF.\n */\n    static void lwg_parse_yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )\n\n{\n\tint oerrno = errno;\n    \n\tlwg_parse_yy_flush_buffer(b );\n\n\tb->yy_input_file = file;\n\tb->yy_fill_buffer = 1;\n\n    /* If b is the current buffer, then lwg_parse_yy_init_buffer was _probably_\n     * called from lwg_parse_yyrestart() or through yy_get_next_buffer.\n     * In that case, we don't want to reset the lineno or column.\n     */\n    if (b != YY_CURRENT_BUFFER){\n        b->yy_bs_lineno = 1;\n        b->yy_bs_column = 0;\n    }\n\n        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;\n    \n\terrno = oerrno;\n}\n\n/** Discard all buffered characters. On the next scan, YY_INPUT will be called.\n * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.\n * \n */\n    void lwg_parse_yy_flush_buffer (YY_BUFFER_STATE  b )\n{\n    \tif ( ! b )\n\t\treturn;\n\n\tb->yy_n_chars = 0;\n\n\t/* We always need two end-of-buffer characters.  The first causes\n\t * a transition to the end-of-buffer state.  The second causes\n\t * a jam in that state.\n\t */\n\tb->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;\n\tb->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;\n\n\tb->yy_buf_pos = &b->yy_ch_buf[0];\n\n\tb->yy_at_bol = 1;\n\tb->yy_buffer_status = YY_BUFFER_NEW;\n\n\tif ( b == YY_CURRENT_BUFFER )\n\t\tlwg_parse_yy_load_buffer_state( );\n}\n\n/** Pushes the new state onto the stack. The new state becomes\n *  the current state. This function will allocate the stack\n *  if necessary.\n *  @param new_buffer The new state.\n *  \n */\nvoid lwg_parse_yypush_buffer_state (YY_BUFFER_STATE new_buffer )\n{\n    \tif (new_buffer == NULL)\n\t\treturn;\n\n\tlwg_parse_yyensure_buffer_stack();\n\n\t/* This block is copied from lwg_parse_yy_switch_to_buffer. */\n\tif ( YY_CURRENT_BUFFER )\n\t\t{\n\t\t/* Flush out information for old buffer. */\n\t\t*(yy_c_buf_p) = (yy_hold_char);\n\t\tYY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);\n\t\tYY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);\n\t\t}\n\n\t/* Only push if top exists. Otherwise, replace top. */\n\tif (YY_CURRENT_BUFFER)\n\t\t(yy_buffer_stack_top)++;\n\tYY_CURRENT_BUFFER_LVALUE = new_buffer;\n\n\t/* copied from lwg_parse_yy_switch_to_buffer. */\n\tlwg_parse_yy_load_buffer_state( );\n\t(yy_did_buffer_switch_on_eof) = 1;\n}\n\n/** Removes and deletes the top of the stack, if present.\n *  The next element becomes the new top.\n *  \n */\nvoid lwg_parse_yypop_buffer_state (void)\n{\n    \tif (!YY_CURRENT_BUFFER)\n\t\treturn;\n\n\tlwg_parse_yy_delete_buffer(YY_CURRENT_BUFFER );\n\tYY_CURRENT_BUFFER_LVALUE = NULL;\n\tif ((yy_buffer_stack_top) > 0)\n\t\t--(yy_buffer_stack_top);\n\n\tif (YY_CURRENT_BUFFER) {\n\t\tlwg_parse_yy_load_buffer_state( );\n\t\t(yy_did_buffer_switch_on_eof) = 1;\n\t}\n}\n\n/* Allocates the stack if it does not exist.\n *  Guarantees space for at least one push.\n */\nstatic void lwg_parse_yyensure_buffer_stack (void)\n{\n\tint num_to_alloc;\n    \n\tif (!(yy_buffer_stack)) {\n\n\t\t/* First allocation is just for 2 elements, since we don't know if this\n\t\t * scanner will even need a stack. We use 2 instead of 1 to avoid an\n\t\t * immediate realloc on the next call.\n         */\n\t\tnum_to_alloc = 1;\n\t\t(yy_buffer_stack) = (struct yy_buffer_state**)lwg_parse_yyalloc\n\t\t\t\t\t\t\t\t(num_to_alloc * sizeof(struct yy_buffer_state*)\n\t\t\t\t\t\t\t\t);\n\t\tif ( ! (yy_buffer_stack) )\n\t\t\tYY_FATAL_ERROR( \"out of dynamic memory in lwg_parse_yyensure_buffer_stack()\" );\n\t\t\t\t\t\t\t\t  \n\t\tmemset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));\n\t\t\t\t\n\t\t(yy_buffer_stack_max) = num_to_alloc;\n\t\t(yy_buffer_stack_top) = 0;\n\t\treturn;\n\t}\n\n\tif ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){\n\n\t\t/* Increase the buffer to prepare for a possible push. */\n\t\tint grow_size = 8 /* arbitrary grow size */;\n\n\t\tnum_to_alloc = (yy_buffer_stack_max) + grow_size;\n\t\t(yy_buffer_stack) = (struct yy_buffer_state**)lwg_parse_yyrealloc\n\t\t\t\t\t\t\t\t((yy_buffer_stack),\n\t\t\t\t\t\t\t\tnum_to_alloc * sizeof(struct yy_buffer_state*)\n\t\t\t\t\t\t\t\t);\n\t\tif ( ! (yy_buffer_stack) )\n\t\t\tYY_FATAL_ERROR( \"out of dynamic memory in lwg_parse_yyensure_buffer_stack()\" );\n\n\t\t/* zero only the new slots.*/\n\t\tmemset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));\n\t\t(yy_buffer_stack_max) = num_to_alloc;\n\t}\n}\n\n/** Setup the input buffer state to scan directly from a user-specified character buffer.\n * @param base the character buffer\n * @param size the size in bytes of the character buffer\n * \n * @return the newly allocated buffer state object. \n */\nYY_BUFFER_STATE lwg_parse_yy_scan_buffer  (char * base, yy_size_t  size )\n{\n\tYY_BUFFER_STATE b;\n    \n\tif ( size < 2 ||\n\t     base[size-2] != YY_END_OF_BUFFER_CHAR ||\n\t     base[size-1] != YY_END_OF_BUFFER_CHAR )\n\t\t/* They forgot to leave room for the EOB's. */\n\t\treturn 0;\n\n\tb = (YY_BUFFER_STATE) lwg_parse_yyalloc(sizeof( struct yy_buffer_state )  );\n\tif ( ! b )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in lwg_parse_yy_scan_buffer()\" );\n\n\tb->yy_buf_size = size - 2;\t/* \"- 2\" to take care of EOB's */\n\tb->yy_buf_pos = b->yy_ch_buf = base;\n\tb->yy_is_our_buffer = 0;\n\tb->yy_input_file = 0;\n\tb->yy_n_chars = b->yy_buf_size;\n\tb->yy_is_interactive = 0;\n\tb->yy_at_bol = 1;\n\tb->yy_fill_buffer = 0;\n\tb->yy_buffer_status = YY_BUFFER_NEW;\n\n\tlwg_parse_yy_switch_to_buffer(b  );\n\n\treturn b;\n}\n\n/** Setup the input buffer state to scan a string. The next call to lwg_parse_yylex() will\n * scan from a @e copy of @a str.\n * @param yystr a NUL-terminated string to scan\n * \n * @return the newly allocated buffer state object.\n * @note If you want to scan bytes that may contain NUL values, then use\n *       lwg_parse_yy_scan_bytes() instead.\n */\nYY_BUFFER_STATE lwg_parse_yy_scan_string (yyconst char * yystr )\n{\n    \n\treturn lwg_parse_yy_scan_bytes(yystr,strlen(yystr) );\n}\n\n/** Setup the input buffer state to scan the given bytes. The next call to lwg_parse_yylex() will\n * scan from a @e copy of @a bytes.\n * @param bytes the byte buffer to scan\n * @param len the number of bytes in the buffer pointed to by @a bytes.\n * \n * @return the newly allocated buffer state object.\n */\nYY_BUFFER_STATE lwg_parse_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )\n{\n\tYY_BUFFER_STATE b;\n\tchar *buf;\n\tyy_size_t n;\n\tint i;\n    \n\t/* Get memory for full buffer, including space for trailing EOB's. */\n\tn = _yybytes_len + 2;\n\tbuf = (char *) lwg_parse_yyalloc(n  );\n\tif ( ! buf )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in lwg_parse_yy_scan_bytes()\" );\n\n\tfor ( i = 0; i < _yybytes_len; ++i )\n\t\tbuf[i] = yybytes[i];\n\n\tbuf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;\n\n\tb = lwg_parse_yy_scan_buffer(buf,n );\n\tif ( ! b )\n\t\tYY_FATAL_ERROR( \"bad buffer in lwg_parse_yy_scan_bytes()\" );\n\n\t/* It's okay to grow etc. this buffer, and we should throw it\n\t * away when we're done.\n\t */\n\tb->yy_is_our_buffer = 1;\n\n\treturn b;\n}\n\n#ifndef YY_EXIT_FAILURE\n#define YY_EXIT_FAILURE 2\n#endif\n\nstatic void yy_fatal_error (yyconst char* msg )\n{\n    \t(void) fprintf( stderr, \"%s\\n\", msg );\n\texit( YY_EXIT_FAILURE );\n}\n\n/* Redefine yyless() so it works in section 3 code. */\n\n#undef yyless\n#define yyless(n) \\\n\tdo \\\n\t\t{ \\\n\t\t/* Undo effects of setting up lwg_parse_yytext. */ \\\n        int yyless_macro_arg = (n); \\\n        YY_LESS_LINENO(yyless_macro_arg);\\\n\t\tlwg_parse_yytext[lwg_parse_yyleng] = (yy_hold_char); \\\n\t\t(yy_c_buf_p) = lwg_parse_yytext + yyless_macro_arg; \\\n\t\t(yy_hold_char) = *(yy_c_buf_p); \\\n\t\t*(yy_c_buf_p) = '\\0'; \\\n\t\tlwg_parse_yyleng = yyless_macro_arg; \\\n\t\t} \\\n\twhile ( 0 )\n\n/* Accessor  methods (get/set functions) to struct members. */\n\n/** Get the current line number.\n * \n */\nint lwg_parse_yyget_lineno  (void)\n{\n        \n    return lwg_parse_yylineno;\n}\n\n/** Get the input stream.\n * \n */\nFILE *lwg_parse_yyget_in  (void)\n{\n        return lwg_parse_yyin;\n}\n\n/** Get the output stream.\n * \n */\nFILE *lwg_parse_yyget_out  (void)\n{\n        return lwg_parse_yyout;\n}\n\n/** Get the length of the current token.\n * \n */\nint lwg_parse_yyget_leng  (void)\n{\n        return lwg_parse_yyleng;\n}\n\n/** Get the current token.\n * \n */\n\nchar *lwg_parse_yyget_text  (void)\n{\n        return lwg_parse_yytext;\n}\n\n/** Set the current line number.\n * @param line_number\n * \n */\nvoid lwg_parse_yyset_lineno (int  line_number )\n{\n    \n    lwg_parse_yylineno = line_number;\n}\n\n/** Set the input stream. This does not discard the current\n * input buffer.\n * @param in_str A readable stream.\n * \n * @see lwg_parse_yy_switch_to_buffer\n */\nvoid lwg_parse_yyset_in (FILE *  in_str )\n{\n        lwg_parse_yyin = in_str ;\n}\n\nvoid lwg_parse_yyset_out (FILE *  out_str )\n{\n        lwg_parse_yyout = out_str ;\n}\n\nint lwg_parse_yyget_debug  (void)\n{\n        return lwg_parse_yy_flex_debug;\n}\n\nvoid lwg_parse_yyset_debug (int  bdebug )\n{\n        lwg_parse_yy_flex_debug = bdebug ;\n}\n\nstatic int yy_init_globals (void)\n{\n        /* Initialization is the same as for the non-reentrant scanner.\n     * This function is called from lwg_parse_yylex_destroy(), so don't allocate here.\n     */\n\n    (yy_buffer_stack) = 0;\n    (yy_buffer_stack_top) = 0;\n    (yy_buffer_stack_max) = 0;\n    (yy_c_buf_p) = (char *) 0;\n    (yy_init) = 0;\n    (yy_start) = 0;\n\n/* Defined in main.c */\n#ifdef YY_STDINIT\n    lwg_parse_yyin = stdin;\n    lwg_parse_yyout = stdout;\n#else\n    lwg_parse_yyin = (FILE *) 0;\n    lwg_parse_yyout = (FILE *) 0;\n#endif\n\n    /* For future reference: Set errno on error, since we are called by\n     * lwg_parse_yylex_init()\n     */\n    return 0;\n}\n\n/* lwg_parse_yylex_destroy is for both reentrant and non-reentrant scanners. */\nint lwg_parse_yylex_destroy  (void)\n{\n    \n    /* Pop the buffer stack, destroying each element. */\n\twhile(YY_CURRENT_BUFFER){\n\t\tlwg_parse_yy_delete_buffer(YY_CURRENT_BUFFER  );\n\t\tYY_CURRENT_BUFFER_LVALUE = NULL;\n\t\tlwg_parse_yypop_buffer_state();\n\t}\n\n\t/* Destroy the stack itself. */\n\tlwg_parse_yyfree((yy_buffer_stack) );\n\t(yy_buffer_stack) = NULL;\n\n    /* Reset the globals. This is important in a non-reentrant scanner so the next time\n     * lwg_parse_yylex() is called, initialization will occur. */\n    yy_init_globals( );\n\n    return 0;\n}\n\n/*\n * Internal utility routines.\n */\n\n#ifndef yytext_ptr\nstatic void yy_flex_strncpy (char* s1, yyconst char * s2, int n )\n{\n\tregister int i;\n\tfor ( i = 0; i < n; ++i )\n\t\ts1[i] = s2[i];\n}\n#endif\n\n#ifdef YY_NEED_STRLEN\nstatic int yy_flex_strlen (yyconst char * s )\n{\n\tregister int n;\n\tfor ( n = 0; s[n]; ++n )\n\t\t;\n\n\treturn n;\n}\n#endif\n\nvoid *lwg_parse_yyalloc (yy_size_t  size )\n{\n\treturn (void *) malloc( size );\n}\n\nvoid *lwg_parse_yyrealloc  (void * ptr, yy_size_t  size )\n{\n\t/* The cast to (char *) in the following accommodates both\n\t * implementations that use char* generic pointers, and those\n\t * that use void* generic pointers.  It works with the latter\n\t * because both ANSI C and C++ allow castless assignment from\n\t * any pointer type to void*, and deal with argument conversions\n\t * as though doing an assignment.\n\t */\n\treturn (void *) realloc( (char *) ptr, size );\n}\n\nvoid lwg_parse_yyfree (void * ptr )\n{\n\tfree( (char *) ptr );\t/* see lwg_parse_yyrealloc() for (char *) cast */\n}\n\n#define YYTABLES_NAME \"yytables\"\n\n#line 73 \"wktparse.lex\"\n\n\n\n\n"
  },
  {
    "path": "src/liblwgeom/liblwgeom.h",
    "content": "/**********************************************************************\n * $Id: liblwgeom.h 3812 2009-03-09 14:36:15Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n * Copyright 2007-2008 Mark Cave-Ayland\n * Copyright 2008 Paul Ramsey <pramsey@cleverelephant.ca>\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#ifndef _LIBLWGEOM_H\n#define _LIBLWGEOM_H 1\n\n#include \"postgis_config.h\"\n#include <stdarg.h>\n#include <stdio.h>\n\n/**\n* @file liblwgeom.h\n* \n* This library is the generic geometry handling section of PostGIS. The geometry\n* objects, constructors, destructors, and a set of spatial processing functions,\n* are implemented here. \n* \n* The library is designed for use in non-PostGIS applications if necessary. The \n* units tests at cunit/cu_tester.c and the loader/dumper programs at \n* ../loader/shp2pgsql.c are examples of non-PostGIS applications using liblwgeom.\n* \n* Programs using this library should set up the default memory managers and error\n* handlers by implementing an lwgeom_init_allocators() function, which can be as \n* a wrapper around the lwgeom_install_default_allocators() function if you want\n* no special handling for memory management and error reporting.\n*/\n\n#define INTEGRITY_CHECKS 1\n\n/*\n * Floating point comparitors.\n */\n#define PGIS_EPSILON 1e-12\n#define FP_MAX(A, B) ((A > B) ? A : B)\n#define FP_MIN(A, B) ((A < B) ? A : B)\n#define FP_LT(A, B) ((A + PGIS_EPSILON) < B)\n#define FP_LTEQ(A, B) ((A - PGIS_EPSILON) <= B)\n#define FP_GT(A, B) ((A - PGIS_EPSILON) > B)\n#define FP_GTEQ(A, B) ((A + PGIS_EPSILON) >= B)\n#define FP_CONTAINS_TOP(A, X, B) (FP_LT(A, X) && FP_LTEQ(X, B))\n#define FP_CONTAINS_BOTTOM(A, X, B) (FP_LTEQ(A, X) && FP_LT(X, B))\n#define FP_CONTAINS_INCL(A, X, B) (FP_LTEQ(A, X) && FP_LTEQ(X, B))\n#define FP_CONTAINS_EXCL(A, X, B) (FP_LT(A, X) && FP_LT(X, B))\n#define FP_CONTAINS(A, X, B) FP_CONTAINS_EXCL(A, X, B)\n#define LW_TRUE 1\n#define LW_FALSE 0\n\n/*\n* this will change to NaN when I figure out how to\n* get NaN in a platform-independent way\n*/\n#define NO_VALUE 0.0\n#define NO_Z_VALUE NO_VALUE\n#define NO_M_VALUE NO_VALUE\n\n#ifndef C_H\n\ntypedef unsigned int uint32;\ntypedef int int32;\n\n#endif\n\n/** \n* Global functions for memory/logging handlers. \n*/\ntypedef void* (*lwallocator)(size_t size);\ntypedef void* (*lwreallocator)(void *mem, size_t size);\ntypedef void (*lwfreeor)(void* mem);\ntypedef void (*lwreporter)(const char* fmt, va_list ap);\nextern lwreallocator lwrealloc_var;\nextern lwallocator lwalloc_var;\nextern lwfreeor lwfree_var;\nextern lwreporter lwerror_var;\nextern lwreporter lwnotice_var;\n\n/**\n* Supply the memory management and error handling functions you want your\n* application to use.\n* @ingroup system\n*/\nextern void lwgeom_init_allocators(void);\n\n/**\n* Apply the default memory management (malloc() and free()) and error handlers.\n* Called inside lwgeom_init_allocators() generally.\n* @ingroup system\n*/\nextern void lwgeom_install_default_allocators(void);\n\n/**\n* Write a notice out to the notice handler. Uses standard printf() substitutions.\n* Use for messages you always want output. For debugging, use LWDEBUG() or LWDEBUGF().\n* @ingroup logging\n*/\nvoid lwnotice(const char *fmt, ...);\n\n/**\n* Write a notice out to the error handler. Uses standard printf() substitutions.\n* Use for errors you always want output. For debugging, use LWDEBUG() or LWDEBUGF().\n* @ingroup logging\n*/\nvoid lwerror(const char *fmt, ...);\n\n/**\n* The default memory/logging handlers installed by lwgeom_install_default_allocators() \n*/\nvoid *default_allocator(size_t size);\nvoid *default_reallocator(void *mem, size_t size);\nvoid default_freeor(void *ptr);\nvoid default_errorreporter(const char *fmt, va_list ap);\nvoid default_noticereporter(const char *fmt, va_list ap);\n\n\nextern int lw_vasprintf (char **result, const char *format, va_list args);\n\n/* Debug macros */\n#if POSTGIS_DEBUG_LEVEL > 0\n\n/* Display a notice at the given debug level */\n#define LWDEBUG(level, msg) \\\n        do { \\\n                if (POSTGIS_DEBUG_LEVEL >= level) \\\n                        lwnotice(\"[%s:%s:%d] \" msg, __FILE__, __func__, __LINE__); \\\n        } while (0);\n\n/* Display a formatted notice at the given debug level (like printf, with variadic arguments) */\n#define LWDEBUGF(level, msg, ...) \\\n        do { \\\n                if (POSTGIS_DEBUG_LEVEL >= level) \\\n                        lwnotice(\"[%s:%s:%d] \" msg, __FILE__, __func__, __LINE__, __VA_ARGS__); \\\n        } while (0);\n\n#else\n\n/* Empty prototype that can be optimised away by the compiler for non-debug builds */\n#define LWDEBUG(level, msg) \\\n        ((void) 0)\n\n/* Empty prototype that can be optimised away by the compiler for non-debug builds */\n#define LWDEBUGF(level, msg, ...) \\\n        ((void) 0)\n\n#endif\n\n/******************************************************************/\n\ntypedef unsigned char uchar;\n\ntypedef struct\n{\n\tfloat xmin;\n\tfloat ymin;\n\tfloat xmax;\n\tfloat ymax;\n} BOX2DFLOAT4;\n\ntypedef struct\n{\n        double xmin, ymin, zmin;\n        double xmax, ymax, zmax;\n} BOX3D;\n\ntypedef struct chiptag\n{\n\tint size; /* unused (for use by postgresql) */\n\n\tint endian_hint; /* the number 1 in the endian of this datastruct */\n\n\tBOX3D bvol;\n\tint SRID;\n\tchar future[4];\n\tfloat factor;\t/* Usually 1.0.\n\t\t\t * Integer values are multiplied by this number\n\t\t\t * to get the actual height value\n\t\t\t * (for sub-meter accuracy height data).\n\t\t\t */\n\n\tint datatype;\t/* 1 = float32,\n\t\t\t * 5 = 24bit integer,\n\t\t\t * 6 = 16bit integer (short)\n\t\t\t * 7 = 16bit ???\n\t\t\t * 8 = 8bit ???\n\t\t\t * 101 = float32 (NDR),\n\t\t\t * 105 = 24bit integer (NDR),\n\t\t\t * 106 = 16bit int (NDR)\n\t\t\t * 107 = 16bit ??? (NDR)\n\t\t\t * 108 = 8bit ??? (NDR) (this doesn't make sense)\n\t\t\t */\n\tint height;\n\tint width;\n\tint compression;\t/* 0 = no compression, 1 = differencer\n\t\t\t\t * 0x80 = new value\n\t\t\t\t * 0x7F = nodata\n\t\t\t\t */\n\n\t/*\n\t * this is provided for convenience, it should be set to\n\t *  sizeof(chip) bytes into the struct because the serialized form is:\n\t *    <header><data>\n\t * NULL when serialized\n\t */\n\tvoid  *data;\t/* data[0] = bottm left,\n\t\t\t * data[width] = 1st pixel, 2nd row (uncompressed)\n\t\t\t */\n\n} CHIP;\n\n/*\n * standard definition of an ellipsoid (what wkt calls a spheroid)\n *    f = (a-b)/a\n *    e_sq = (a*a - b*b)/(a*a)\n *    b = a - fa\n */\ntypedef struct\n{\n\tdouble\ta;\t/* semimajor axis */\n\tdouble\tb; \t/* semiminor axis */\n\tdouble\tf;\t/* flattening     */\n\tdouble\te;\t/* eccentricity (first) */\n\tdouble\te_sq;\t/* eccentricity (first), squared */\n\tchar\tname[20]; /* name of ellipse */\n} SPHEROID;\n\n\n/*\n * ALL LWGEOM structures will use POINT3D as an abstract point.\n * This means a 2d geometry will be stored as (x,y) in its serialized\n * form, but all functions will work on (x,y,0).  This keeps all the\n * analysis functions simple.\n * NOTE: for GEOS integration, we'll probably set z=NaN\n *        so look out - z might be NaN for 2d geometries!\n */\ntypedef struct { double\tx,y,z; } POINT3DZ;\ntypedef struct { double\tx,y,z; } POINT3D; /* alias for POINT3DZ */\ntypedef struct { double\tx,y,m; } POINT3DM;\n\n\n/*\n * type for 2d points.  When you convert this to 3d, the\n *   z component will be either 0 or NaN.\n */\ntypedef struct\n{\n\t double x;\n\t double y;\n} POINT2D;\n\ntypedef struct\n{\n\t double x;\n\t double y;\n\t double z;\n\t double m;\n} POINT4D;\n\n/******************************************************************/\n\n/*\n * Point array abstracts a lot of the complexity of points and point lists.\n * It handles miss-alignment in the serialized form, 2d/3d translation\n *    (2d points converted to 3d will have z=0 or NaN)\n * DONT MIX 2D and 3D POINTS!  *EVERYTHING* is either one or the other\n */\ntypedef struct\n{\n    /* array of POINT 2D, 3D or 4D. probably missaligned. */\n    uchar *serialized_pointlist;\n\n    /* use TYPE_* macros to handle */\n    uchar  dims;\n\n    uint32 npoints;\n}  POINTARRAY;\n\n\n/*\n * Use the following to build pointarrays\n * when number of points in output is not \n * known in advance\n */\ntypedef struct {\n\tPOINTARRAY *pa;\n\tsize_t ptsize;\n\tsize_t capacity; /* given in points */\n} DYNPTARRAY;\n\n/* Create a new dynamic pointarray */\nextern DYNPTARRAY *dynptarray_create(size_t initial_capacity, int dims);\n\n/*\n * Add a POINT4D to the dynamic pointarray.\n *\n * The dynamic pointarray may be of any dimension, only\n * accepted dimensions will be copied.\n *\n * If allow_duplicates is set to 0 (false) a check\n * is performed to see if last point in array is equal to the\n * provided one. NOTE that the check is 4d based, with missing\n * ordinates in the pointarray set to NO_Z_VALUE and NO_M_VALUE\n * respectively.\n */\nextern int dynptarray_addPoint4d(DYNPTARRAY *dpa, POINT4D *p4d,\n\tint allow_duplicates);\n\n/******************************************************************\n *\n * LWGEOM (any type)\n *\n ******************************************************************/\n\ntypedef struct\n{\n\tuchar type; \n\tBOX2DFLOAT4 *bbox;\n\tuint32 SRID; /* -1 == unneeded */\n\tvoid *data;\n} LWGEOM;\n\n/* POINTYPE */\ntypedef struct\n{\n\tuchar type; /* POINTTYPE */\n\tBOX2DFLOAT4 *bbox;\n   \tuint32 SRID;\t\n   \tPOINTARRAY *point;  /* hide 2d/3d (this will be an array of 1 point) */\n}  LWPOINT; /* \"light-weight point\" */\n\n/* LINETYPE */\ntypedef struct\n{\n\tuchar type; /* LINETYPE */\n\tBOX2DFLOAT4 *bbox;\n   \tuint32 SRID;\t\n\tPOINTARRAY    *points; /* array of POINT3D */\n} LWLINE; /* \"light-weight line\" */\n\n/* POLYGONTYPE */\ntypedef struct\n{\n\tuchar type; /* POLYGONTYPE */\n\tBOX2DFLOAT4 *bbox;\n   \tuint32 SRID;\t\n\tint  nrings;\n\tPOINTARRAY **rings; /* list of rings (list of points) */\n} LWPOLY; /* \"light-weight polygon\" */\n\n/* MULTIPOINTTYPE */\ntypedef struct\n{\n\tuchar type;  \n\tBOX2DFLOAT4 *bbox;\n   \tuint32 SRID;\t\n\tint  ngeoms;\n\tLWPOINT **geoms;\n} LWMPOINT; \n\n/* MULTILINETYPE */\ntypedef struct\n{  \n\tuchar type; \n\tBOX2DFLOAT4 *bbox;\n   \tuint32 SRID;\t\n\tint  ngeoms;\n\tLWLINE **geoms;\n} LWMLINE; \n\n/* MULTIPOLYGONTYPE */\ntypedef struct\n{  \n\tuchar type; \n\tBOX2DFLOAT4 *bbox;\n   \tuint32 SRID;\t\n\tint  ngeoms;\n\tLWPOLY **geoms;\n} LWMPOLY; \n\n/* COLLECTIONTYPE */\ntypedef struct\n{   \n\tuchar type; \n\tBOX2DFLOAT4 *bbox;\n   \tuint32 SRID;\t\n\tint  ngeoms;\n\tLWGEOM **geoms;\n} LWCOLLECTION; \n\n/* CIRCSTRINGTYPE */\ntypedef struct\n{\n        uchar type; /* CIRCSTRINGTYPE */\n        BOX2DFLOAT4 *bbox;\n        uint32 SRID;\n        POINTARRAY *points; /* array of POINT(3D/3DM) */\n} LWCIRCSTRING; /* \"light-weight circularstring\" */\n\n/* COMPOUNDTYPE */\ntypedef struct\n{\n        uchar type; /* COMPOUNDTYPE */\n        BOX2DFLOAT4 *bbox;\n        uint32 SRID;\n        int ngeoms;\n        LWGEOM **geoms;\n} LWCOMPOUND; /* \"light-weight compound line\" */\n\n/* CURVEPOLYTYPE */\ntypedef struct\n{\n        uchar type; /* CURVEPOLYTYPE */\n        BOX2DFLOAT4 *bbox;\n        uint32 SRID;\n        int nrings;\n        LWGEOM **rings; /* list of rings (list of points) */\n} LWCURVEPOLY; /* \"light-weight polygon\" */\n\n/* MULTICURVE */\ntypedef struct\n{\n        uchar type;\n        BOX2DFLOAT4 *bbox;\n        uint32 SRID;\n        int ngeoms;\n        LWGEOM **geoms;\n} LWMCURVE;\n\n/* MULTISURFACETYPE */\ntypedef struct\n{\n        uchar type;\n        BOX2DFLOAT4 *bbox;\n        uint32 SRID;\n        int ngeoms;\n        LWGEOM **geoms;\n} LWMSURFACE;\n\n/* Casts LWGEOM->LW* (return NULL if cast is illegal) */\nextern LWMPOLY *lwgeom_as_lwmpoly(LWGEOM *lwgeom);\nextern LWMLINE *lwgeom_as_lwmline(LWGEOM *lwgeom);\nextern LWMPOINT *lwgeom_as_lwmpoint(LWGEOM *lwgeom);\nextern LWCOLLECTION *lwgeom_as_lwcollection(LWGEOM *lwgeom);\nextern LWPOLY *lwgeom_as_lwpoly(LWGEOM *lwgeom);\nextern LWLINE *lwgeom_as_lwline(LWGEOM *lwgeom);\nextern LWPOINT *lwgeom_as_lwpoint(LWGEOM *lwgeom);\nextern LWCIRCSTRING *lwgeom_as_lwcircstring(LWGEOM *lwgeom);\n\n/* Casts LW*->LWGEOM (always cast) */\nextern LWGEOM *lwmpoly_as_lwgeom(LWMPOLY *obj);\nextern LWGEOM *lwmline_as_lwgeom(LWMLINE *obj);\nextern LWGEOM *lwmpoint_as_lwgeom(LWMPOINT *obj);\nextern LWGEOM *lwcollection_as_lwgeom(LWCOLLECTION *obj);\nextern LWGEOM *lwpoly_as_lwgeom(LWPOLY *obj);\nextern LWGEOM *lwline_as_lwgeom(LWLINE *obj);\nextern LWGEOM *lwpoint_as_lwgeom(LWPOINT *obj);\n\n/*\n * Call this function everytime LWGEOM coordinates \n * change so to invalidate bounding box\n */\nextern void lwgeom_changed(LWGEOM *lwgeom);\n\n/*\n * Call this function to drop BBOX and SRID\n * from LWGEOM. If LWGEOM type is *not* flagged\n * with the HASBBOX flag and has a bbox, it\n * will be released.\n */\nextern void lwgeom_drop_bbox(LWGEOM *lwgeom);\n\n/* Compute a bbox if not already computed */\nextern void lwgeom_add_bbox(LWGEOM *lwgeom);\n\nextern void lwgeom_dropSRID(LWGEOM *lwgeom);\n\n/* Determine whether a LWGEOM can contain sub-geometries or not */\nextern int lwgeom_contains_subgeoms(int type);\n\n/******************************************************************/\n\n/*\n * copies a point from the point array into the parameter point\n * will set point's z=0 (or NaN) if pa is 2d\n * will set point's m=0 (or NaN) if pa is 3d or 2d\n * NOTE: point is a real POINT3D *not* a pointer\n */\nextern POINT4D getPoint4d(const POINTARRAY *pa, int n);\n\n/*\n * copies a point from the point array into the parameter point\n * will set point's z=0 (or NaN) if pa is 2d\n * will set point's m=0 (or NaN) if pa is 3d or 2d\n * NOTE: this will modify the point4d pointed to by 'point'.\n */\nextern int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point);\n\n/*\n * copies a point from the point array into the parameter point\n * will set point's z=0 (or NaN) if pa is 2d\n * NOTE: point is a real POINT3D *not* a pointer\n */\nextern POINT3DZ getPoint3dz(const POINTARRAY *pa, int n);\nextern POINT3DM getPoint3dm(const POINTARRAY *pa, int n);\n\n/*\n * copies a point from the point array into the parameter point\n * will set point's z=0 (or NaN) if pa is 2d\n * NOTE: this will modify the point3d pointed to by 'point'.\n */\nextern int getPoint3dz_p(const POINTARRAY *pa, int n, POINT3DZ *point);\nextern int getPoint3dm_p(const POINTARRAY *pa, int n, POINT3DM *point);\n\n\n/*\n * copies a point from the point array into the parameter point\n * z value (if present is not returned)\n * NOTE: point is a real POINT3D *not* a pointer\n */\nextern POINT2D getPoint2d(const POINTARRAY *pa, int n);\n\n/*\n * copies a point from the point array into the parameter point\n * z value (if present is not returned)\n * NOTE: this will modify the point2d pointed to by 'point'.\n */\nextern int getPoint2d_p(const POINTARRAY *pa, int n, POINT2D *point);\n\n/*\n * set point N to the given value\n * NOTE that the pointarray can be of any\n * dimension, the appropriate ordinate values\n * will be extracted from it\n *\n */\nextern void setPoint4d(POINTARRAY *pa, int n, POINT4D *p4d);\n\n/*\n * get a pointer to nth point of a POINTARRAY\n * You'll need to cast it to appropriate dimensioned point.\n * Note that if you cast to a higher dimensional point you'll\n * possibly corrupt the POINTARRAY.\n *\n * WARNING: Don't cast this to a POINT !\n * it would not be reliable due to memory alignment constraints \n */\nextern uchar *getPoint_internal(const POINTARRAY *pa, int n);\n\n/* --- here is a macro equivalent, for speed... */\n/* #define getPoint(x,n) &( (x)->serialized_pointlist[((x)->ndims*8)*(n)] ) */\n\n\n/*\n * constructs a POINTARRAY.\n * NOTE: points is *not* copied, so be careful about modification\n * (can be aligned/missaligned)\n * NOTE: hasz and hasm are descriptive - it describes what type of data\n *\t 'points' points to.  No data conversion is done.\n */\nextern POINTARRAY *pointArray_construct(uchar *points, char hasz, char hasm,\n\tuint32 npoints);\n\n/* \n * Calculate the (BOX3D) bounding box of a set of points.\n * Returns an alloced BOX3D or NULL (for empty geom) in the first form.\n * Write result in user-provided BOX3D in second form (return 0 if untouched).\n * If pa is 2d, then box3d's zmin/zmax will be set to NO_Z_VALUE\n */\nextern BOX3D *ptarray_compute_box3d(const POINTARRAY *pa);\nextern int ptarray_compute_box3d_p(const POINTARRAY *pa, BOX3D *out);\n\n/*\n * size of point represeneted in the POINTARRAY\n * 16 for 2d, 24 for 3d, 32 for 4d\n */\nextern int pointArray_ptsize(const POINTARRAY *pa);\n\n\n#define\tPOINTTYPE\t1\n#define\tLINETYPE\t2\n#define\tPOLYGONTYPE\t3\n#define\tMULTIPOINTTYPE\t4\n#define\tMULTILINETYPE\t5\n#define\tMULTIPOLYGONTYPE\t6\n#define\tCOLLECTIONTYPE\t7\n#define CIRCSTRINGTYPE    8\n#define COMPOUNDTYPE      9\n#define CURVEPOLYTYPE    13\n#define MULTICURVETYPE   14\n#define MULTISURFACETYPE 15\n\n#define WKBZOFFSET 0x80000000\n#define WKBMOFFSET 0x40000000\n#define WKBSRIDFLAG 0x20000000\n#define WKBBBOXFLAG 0x10000000\n\n/* These macros work on PG_LWGEOM.type, LWGEOM.type and all its subclasses */\n\n#define TYPE_SETTYPE(c,t) ((c)=(((c)&0xF0)|(t)))\n#define TYPE_SETZM(t,z,m) ((t)=(((t)&0xCF)|((z)<<5)|((m)<<4)))\n#define TYPE_SETHASBBOX(t,b) ((t)=(((t)&0x7F)|((b)<<7)))\n#define TYPE_SETHASSRID(t,s) ((t)=(((t)&0xBF)|((s)<<6)))\n\n#define TYPE_HASZ(t) ( ((t)&0x20)>>5 )\n#define TYPE_HASM(t) ( ((t)&0x10)>>4 )\n#define TYPE_HASBBOX(t) ( ((t)&0x80)>>7 )\n#define TYPE_HASSRID(t) ( (((t)&0x40))>>6 )\n#define TYPE_NDIMS(t) ((((t)&0x20)>>5)+(((t)&0x10)>>4)+2)\n#define TYPE_GETTYPE(t) ((t)&0x0F)\n\n/* 0x02==Z 0x01==M */\n#define TYPE_GETZM(t) (((t)&0x30)>>4)\n\nextern char lwgeom_hasBBOX(uchar type); /* true iff B bit set     */\nextern int  lwgeom_ndims(uchar type);   /* returns 2,3 or 4       */\nextern int  lwgeom_hasZ(uchar type);    /* has Z ?                */\nextern int  lwgeom_hasM(uchar type);    /* has M ?                */\nextern int  lwgeom_getType(uchar type); /* returns the tttt value */\n\nextern uchar lwgeom_makeType(char hasZ, char hasM, char hasSRID, int type);\nextern uchar lwgeom_makeType_full(char hasZ, char hasM, char hasSRID, int type, char hasBBOX);\nextern char lwgeom_hasSRID(uchar type); /* true iff S bit is set */\nextern char lwgeom_hasBBOX(uchar type); /* true iff B bit set    */\n\n\n\n/*\n * This is the binary representation of lwgeom compatible\n * with postgresql varlena struct\n */\ntypedef struct {\n\tuint32 size;        /* varlena header (do not touch directly!) */\n\tuchar type;         /* encodes ndims, type, bbox presence,\n\t\t                srid presence */\n\tuchar data[1];\n} PG_LWGEOM;\n\n/*\n * Construct a full PG_LWGEOM type (including size header)\n * from a serialized form.\n * The constructed PG_LWGEOM object will be allocated using palloc\n * and the serialized form will be copied.\n * If you specify a SRID other then -1 it will be set.\n * If you request bbox (wantbbox=1) it will be extracted or computed\n * from the serialized form.\n */\nextern PG_LWGEOM *PG_LWGEOM_construct(uchar *serialized, int SRID,\n\tint wantbbox);\n\n/*\n * Compute bbox of serialized geom\n */\nextern int compute_serialized_box2d_p(uchar *serialized_form, BOX2DFLOAT4 *box);\nextern BOX3D *compute_serialized_box3d(uchar *serialized_form);\nextern int compute_serialized_box3d_p(uchar *serialized_form, BOX3D *box);\n\n\n/*\n * Evaluate with an heuristic if the provided PG_LWGEOM is worth\n * caching a bbox\n */\nchar is_worth_caching_pglwgeom_bbox(const PG_LWGEOM *);\nchar is_worth_caching_serialized_bbox(const uchar *);\nchar is_worth_caching_lwgeom_bbox(const LWGEOM *);\n\n/*\n * Use this macro to extract the char * required\n * by most functions from an PG_LWGEOM struct.\n * (which is an PG_LWGEOM w/out int32 size casted to char *)\n */\n#define SERIALIZED_FORM(x) ((uchar *)VARDATA((x)))\n\n/*\n * This function computes the size in bytes\n * of the serialized geometries.\n */\nextern size_t lwgeom_size(const uchar *serialized_form);\nextern size_t lwgeom_size_subgeom(const uchar *serialized_form, int geom_number);\nextern size_t lwgeom_size_line(const uchar *serialized_line);\nextern size_t lwgeom_size_circstring(const uchar *serialized_curve);\nextern size_t lwgeom_size_point(const uchar *serialized_point);\nextern size_t lwgeom_size_poly(const uchar *serialized_line);\n\n\n/*--------------------------------------------------------\n * all the base types (point/line/polygon) will have a\n * basic constructor, basic de-serializer, basic serializer,\n * bounding box finder and (TODO) serialized form size finder.\n *--------------------------------------------------------*/\n\n/*\n * given the LWPOINT serialized form (or a pointer into a muli* one)\n * construct a proper LWPOINT.\n * serialized_form should point to the 8bit type format (with type = 1)\n * Returns NULL if serialized form is not a point.\n * See serialized form doc\n */\nextern LWPOINT *lwpoint_deserialize(uchar *serialized_form);\n\n/*\n * Find size this point would get when serialized (no BBOX)\n */\nextern size_t lwpoint_serialize_size(LWPOINT *point);\n\n/*\n * convert this point into its serialize form\n * result's first char will be the 8bit type. \n * See serialized form doc\n */\nextern uchar *lwpoint_serialize(LWPOINT *point);\n\n/* same as above, writes to buf */\nextern void lwpoint_serialize_buf(LWPOINT *point, uchar *buf, size_t *size);\n\n/*\n * find bounding box (standard one) \n * zmin=zmax=0 if 2d (might change to NaN)\n */\nextern BOX3D *lwpoint_compute_box3d(LWPOINT *point);\n\n/*\n * convenience functions to hide the POINTARRAY\n */\nextern int lwpoint_getPoint2d_p(const LWPOINT *point, POINT2D *out);\nextern int lwpoint_getPoint3dz_p(const LWPOINT *point, POINT3DZ *out);\nextern int lwpoint_getPoint3dm_p(const LWPOINT *point, POINT3DM *out);\nextern int lwpoint_getPoint4d_p(const LWPOINT *point, POINT4D *out);\n\n/******************************************************************\n * LWLINE functions\n ******************************************************************/\n\n/*\n * given the LWGEOM serialized form (or a pointer into a muli* one)\n * construct a proper LWLINE.\n * serialized_form should point to the 8bit type format (with type = 2)\n * See SERIALIZED_FORM doc\n */\nextern LWLINE *lwline_deserialize(uchar *serialized_form);\n\n/* find the size this line would get when serialized */\nextern size_t lwline_serialize_size(LWLINE *line);\n\n/*\n * convert this line into its serialize form\n * result's first char will be the 8bit type.  See serialized form doc\n * copies data.\n */\nextern uchar *lwline_serialize(LWLINE *line);\n\n/* same as above, writes to buf */\nextern void lwline_serialize_buf(LWLINE *line, uchar *buf, size_t *size);\n\n/*\n * find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN)\n */\nextern BOX3D *lwline_compute_box3d(LWLINE *line);\n\n/******************************************************************\n * LWPOLY functions\n ******************************************************************/\n\n/*\n * given the LWPOLY serialized form (or a pointer into a muli* one)\n * construct a proper LWPOLY.\n * serialized_form should point to the 8bit type format (with type = 3)\n * See SERIALIZED_FORM doc\n */\nextern LWPOLY *lwpoly_deserialize(uchar *serialized_form);\n\n/* find the size this polygon would get when serialized */\nextern size_t lwpoly_serialize_size(LWPOLY *poly);\n\n/*\n * create the serialized form of the polygon\n * result's first char will be the 8bit type.  See serialized form doc\n * points copied\n */\nextern uchar *lwpoly_serialize(LWPOLY *poly);\n\n/* same as above, writes to buf */\nextern void lwpoly_serialize_buf(LWPOLY *poly, uchar *buf, size_t *size);\n\n/*\n * find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN)\n */\nextern BOX3D *lwpoly_compute_box3d(LWPOLY *poly);\n\n/******************************************************************\n * LWCIRCSTRING functions\n ******************************************************************/\n\n/*\n * given the LWGEOM serialized form (or a pointer into a muli* one)\n * construct a proper LWCIRCSTRING.\n * serialized_form should point to the 8bit type format (with type = 2)\n * See SERIALIZED_FORM doc\n */\nextern LWCIRCSTRING *lwcircstring_deserialize(uchar *serialized_form);\n\n/* find the size this curve would get when serialized */\nextern size_t lwcircstring_serialize_size(LWCIRCSTRING *curve);\n\n/*\n * convert this circularstring into its serialize form\n * result's first char will be the 8bit type.  See serialized form doc\n * copies data.\n */\nextern uchar *lwcircstring_serialize(LWCIRCSTRING *curve);\n\n/* same as above, writes to buf */\nextern void lwcircstring_serialize_buf(LWCIRCSTRING *curve, uchar *buf, size_t *size);\n\n/*\n * find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN)\n */\nextern BOX3D *lwcircstring_compute_box3d(LWCIRCSTRING *curve);\n\n\n\n/******************************************************************\n * LWGEOM functions\n ******************************************************************/\n\nextern size_t lwgeom_serialize_size(LWGEOM *geom);\nextern size_t lwcollection_serialize_size(LWCOLLECTION *coll);\nextern void lwgeom_serialize_buf(LWGEOM *geom, uchar *buf, size_t *size);\nextern uchar *lwgeom_serialize(LWGEOM *geom);\nextern void lwcollection_serialize_buf(LWCOLLECTION *mcoll, uchar *buf, size_t *size);\nextern int lwcollection_ngeoms(const LWCOLLECTION *col);\n\n/*\n * Deserialize an lwgeom serialized form.\n * The deserialized (recursive) structure will store\n * pointers to the serialized form (POINTARRAYs).\n */\nLWGEOM *lwgeom_deserialize(uchar *serializedform);\nBOX3D *lwgeom_compute_box3d(const LWGEOM *geom);\n\n\n/******************************************************************\n * LWMULTIx and LWCOLLECTION functions\n ******************************************************************/\n\nLWMPOINT *lwmpoint_deserialize(uchar *serializedform);\nLWMLINE *lwmline_deserialize(uchar *serializedform);\nLWMPOLY *lwmpoly_deserialize(uchar *serializedform);\nLWCOLLECTION *lwcollection_deserialize(uchar *serializedform);\nLWCOMPOUND *lwcompound_deserialize(uchar *serialized_form);\nLWCURVEPOLY *lwcurvepoly_deserialize(uchar *serialized_form);\nLWMCURVE *lwmcurve_deserialize(uchar *serialized_form);\nLWMSURFACE *lwmsurface_deserialize(uchar *serialized_form);\n\nLWGEOM *lwcollection_getsubgeom(LWCOLLECTION *col, int gnum);\nBOX3D *lwcollection_compute_box3d(LWCOLLECTION *col);\n\n\n/******************************************************************\n * SERIALIZED FORM functions\n ******************************************************************/\n\n\n/******************************************************************\n * Multi-geometries\n *\n * These are all handled equivelently so its easy to write iterator code.\n *  NOTE NOTE: you can hand in a non-multigeometry to most of these functions\n *             and get usual behavior (ie. get geometry 0 on a POINT\n *\t       will return the point).\n *             This makes coding even easier since you dont have to necessarily\n *             differenciate between the multi* and non-multi geometries.\n *\n * NOTE: these usually work directly off the serialized form, so\n *\tthey're a little more difficult to handle (and slower)\n * NOTE NOTE: the get functions maybe slow, so we may want to have an\n *            \"analysed\" lwgeom that would just have pointer to the start\n *            of each sub-geometry.\n *\n ******************************************************************/\n\n/* use this version for speed.  READ-ONLY! */\ntypedef struct\n{\n\tint   SRID;\n\tconst uchar *serialized_form; /* orginal structure */\n\tuchar  type;        /* 8-bit type for the LWGEOM */\n\tint ngeometries;    /* number of sub-geometries */\n\tuchar **sub_geoms;  /* list of pointers (into serialized_form)\n\t\t\t       of the sub-geoms */\n} LWGEOM_INSPECTED;\n\nextern int lwgeom_size_inspected(const LWGEOM_INSPECTED *inspected, int geom_number);\n\n/*\n * note - for a simple type (ie. point), this will have\n * sub_geom[0] = serialized_form.\n * for multi-geomtries sub_geom[0] will be a few bytes into the\n * serialized form.\n * This function just computes the length of each sub-object and\n * pre-caches this info.\n * For a geometry collection of multi* geometries, you can inspect\n * the sub-components as well.\n */\nextern LWGEOM_INSPECTED *lwgeom_inspect(const uchar *serialized_form);\n\n\n/*\n * 1st geometry has geom_number = 0\n * if the actual sub-geometry isnt a POINT, null is returned (see _gettype()).\n * if there arent enough geometries, return null.\n * this is fine to call on a point (with geom_num=0), multipoint\n * or geometrycollection\n */\nextern LWPOINT *lwgeom_getpoint(uchar *serialized_form, int geom_number);\nextern LWPOINT *lwgeom_getpoint_inspected(LWGEOM_INSPECTED *inspected, int geom_number);\n\n/*\n * 1st geometry has geom_number = 0\n * if the actual geometry isnt a LINE, null is returned (see _gettype()).\n * if there arent enough geometries, return null.\n * this is fine to call on a line, multiline or geometrycollection\n */\nextern LWLINE *lwgeom_getline(uchar *serialized_form, int geom_number);\nextern LWLINE *lwgeom_getline_inspected(LWGEOM_INSPECTED *inspected, int geom_number);\n\n/*\n * 1st geometry has geom_number = 0\n * if the actual geometry isnt a POLYGON, null is returned (see _gettype()).\n * if there arent enough geometries, return null.\n * this is fine to call on a polygon, multipolygon or geometrycollection\n */\nextern LWPOLY *lwgeom_getpoly(uchar *serialized_form, int geom_number);\nextern LWPOLY *lwgeom_getpoly_inspected(LWGEOM_INSPECTED *inspected, int geom_number);\n\n/*\n * 1st geometry has geom_number = 0\n * if the actual geometry isnt a POLYGON, null is returned (see _gettype()).\n * if there arent enough geometries, return null.\n * this is fine to call on a polygon, multipolygon or geometrycollection\n */\nextern LWCIRCSTRING *lwgeom_getcircstring_inspected(LWGEOM_INSPECTED *inspected, int geom_number);\n\nextern LWGEOM *lwgeom_getgeom_inspected(LWGEOM_INSPECTED *inspected, int geom_number);\n\n\n\n/*\n * this gets the serialized form of a sub-geometry\n * 1st geometry has geom_number = 0\n * if this isnt a multi* geometry, and geom_number ==0 then it returns\n * itself\n * returns null on problems.\n * in the future this is how you would access a muli* portion of a\n * geometry collection.\n *    GEOMETRYCOLLECTION(MULTIPOINT(0 0, 1 1), LINESTRING(0 0, 1 1))\n *   ie. lwgeom_getpoint( lwgeom_getsubgeometry( serialized, 0), 1)\n *           --> POINT(1 1)\n * you can inspect the sub-geometry as well if you wish.\n */\nextern uchar *lwgeom_getsubgeometry(const uchar *serialized_form, int geom_number);\nextern uchar *lwgeom_getsubgeometry_inspected(LWGEOM_INSPECTED *inspected, int geom_number);\n\n\n/*\n * 1st geometry has geom_number = 0\n *  use geom_number = -1 to find the actual type of the serialized form.\n *    ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, -1)\n *                 --> multipoint\n *   ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, 0)\n *                 --> point\n * gets the 8bit type of the geometry at location geom_number\n */\nextern uchar lwgeom_getsubtype(uchar *serialized_form, int geom_number);\nextern uchar lwgeom_getsubtype_inspected(LWGEOM_INSPECTED *inspected, int geom_number);\n\n\n/*\n * how many sub-geometries are there?\n *  for point,line,polygon will return 1.\n */\nextern int lwgeom_getnumgeometries(uchar *serialized_form);\nextern int lwgeom_getnumgeometries_inspected(LWGEOM_INSPECTED *inspected);\n\n\n\n/*\n * set finalType to COLLECTIONTYPE or 0 (0 means choose a best type)\n *   (ie. give it 2 points and ask it to be a multipoint)\n *  use SRID=-1 for unknown SRID  (will have 8bit type's S = 0)\n * all subgeometries must have the same SRID\n * if you want to construct an inspected, call this then inspect the result...\n */\nextern uchar *lwgeom_serialized_construct(int SRID, int finalType, char hasz, char hasm, int nsubgeometries, uchar **serialized_subs);\n\n\n/* construct the empty geometry (GEOMETRYCOLLECTION(EMPTY)) */\nextern uchar *lwgeom_constructempty(int SRID, char hasz, char hasm);\nextern void lwgeom_constructempty_buf(int SRID, char hasz, char hasm, uchar *buf, size_t *size);\nsize_t lwgeom_empty_length(int SRID);\n\n/*\n * get the SRID from the LWGEOM\n * none present => -1\n */\nextern int lwgeom_getsrid(uchar *serialized);\n\n\n/*------------------------------------------------------\n * other stuff\n *\n * handle the double-to-float conversion.  The results of this\n * will usually be a slightly bigger box because of the difference\n * between float8 and float4 representations.\n */\n\nextern BOX2DFLOAT4 *box3d_to_box2df(BOX3D *box);\nextern int box3d_to_box2df_p(BOX3D *box, BOX2DFLOAT4 *res);\n\nextern BOX3D box2df_to_box3d(BOX2DFLOAT4 *box);\nextern void box2df_to_box3d_p(BOX2DFLOAT4 *box, BOX3D *box3d);\n\nextern BOX3D *box3d_union(BOX3D *b1, BOX3D *b2);\nextern int box3d_union_p(BOX3D *b1, BOX3D *b2, BOX3D *ubox);\n\n/*\n * Returns a pointer to the BBOX internal to the serialized form.\n * READ-ONLY!\n * Or NULL if serialized form does not have a BBOX\n * OBSOLETED to avoid memory alignment problems.\n */\n/*extern BOX2DFLOAT4 *getbox2d_internal(uchar *serialized_form);*/\n\n/*\n * this function writes to 'box' and returns 0 if serialized_form\n * does not have a bounding box (empty geom)\n */\nextern int getbox2d_p(uchar *serialized_form, BOX2DFLOAT4 *box);\n\n/* Expand given box of 'd' units in all directions */\nvoid expand_box2d(BOX2DFLOAT4 *box, double d);\nvoid expand_box3d(BOX3D *box, double d);\n\n/* Check if to boxes are equal (considering FLOAT approximations) */\nchar box2d_same(BOX2DFLOAT4 *box1, BOX2DFLOAT4 *box2);\n\n\n\n/****************************************************************\n * MEMORY MANAGEMENT\n ****************************************************************/\n\n/* \n * The lwfree_* family of functions frees *all* memory associated \n * with the pointer, including the serialized__pointlist in the\n * point arrays. Do not use these on LWGEOMs de-serialized from\n * PG_LWGEOMs or they will try to free an underlying structure\n * managed by PgSQL. Only use these on LWGEOMs you have \n * constructed yourself.\n */\n \nextern void ptarray_free(POINTARRAY *pa);\nextern void lwpoint_free(LWPOINT *pt);\nextern void lwline_free(LWLINE *line);\nextern void lwpoly_free(LWPOLY *poly);\nextern void lwmpoint_free(LWMPOINT *mpt);\nextern void lwmline_free(LWMLINE *mline);\nextern void lwmpoly_free(LWMPOLY *mpoly);\nextern void lwcollection_free(LWCOLLECTION *col);\nextern void lwcircstring_free(LWCIRCSTRING *curve);\nextern void lwgeom_free(LWGEOM *geom);\n\nextern void lwinspected_release(LWGEOM_INSPECTED *inspected); /* TODO: make this deep free... */\n\n/*\n * The *_release family of functions frees the LWGEOM structures\n * surrounding the POINTARRAYs but leaves the POINTARRAYs \n * intact. Use these on LWGEOMs that have been de-serialized\n * from PG_LWGEOMs. Do not use these on LWGEOMs you have \n * constructed yourself, or you will leak lots of memory.\n */\n\nextern void lwpoint_release(LWPOINT *lwpoint);\nextern void lwline_release(LWLINE *lwline);\nextern void lwpoly_release(LWPOLY *lwpoly);\nextern void lwmpoint_release(LWMPOINT *lwpoint);\nextern void lwmline_release(LWMLINE *lwline);\nextern void lwmpoly_release(LWMPOLY *lwpoly);\nextern void lwcollection_release(LWCOLLECTION *lwcollection);\nextern void lwgeom_release(LWGEOM *lwgeom);\n\n\n/****************************************************************\n * utility\n ****************************************************************/\n\nextern uint32 lw_get_uint32(const uchar *loc);\nextern int32 lw_get_int32(const uchar *loc);\nextern void printBOX3D(BOX3D *b);\nextern void printPA(POINTARRAY *pa);\nextern void printLWPOINT(LWPOINT *point);\nextern void printLWLINE(LWLINE *line);\nextern void printLWPOLY(LWPOLY *poly);\nextern void printBYTES(uchar *a, int n);\nextern void printMULTI(uchar *serialized);\nextern void printType(uchar str);\n\n\nextern float LWGEOM_Minf(float a, float b);\nextern float LWGEOM_Maxf(float a, float b);\nextern double LWGEOM_Mind(double a, double b);\nextern double LWGEOM_Maxd(double a, double b);\n\nextern float  nextDown_f(double d);\nextern float  nextUp_f(double d);\nextern double nextDown_d(float d);\nextern double nextUp_d(float d);\n\nextern float nextafterf_custom(float x, float y);\n\n\n#define LW_MAX(a,b) ((a) >\t(b) ? (a) : (b))\n#define LW_MIN(a,b) ((a) <= (b) ? (a) : (b))\n#define LW_ABS(a)   ((a) <\t(0) ? (-a) : (a))\n\n\n/* general utilities */\nextern double lwgeom_polygon_area(LWPOLY *poly);\nextern double lwgeom_polygon_perimeter(LWPOLY *poly);\nextern double lwgeom_polygon_perimeter2d(LWPOLY *poly);\nextern double lwgeom_pointarray_length2d(POINTARRAY *pts);\nextern double lwgeom_pointarray_length(POINTARRAY *pts);\nextern void lwgeom_force2d_recursive(uchar *serialized, uchar *optr, size_t *retsize);\nextern void lwgeom_force3dz_recursive(uchar *serialized, uchar *optr, size_t *retsize);\nextern void lwgeom_force3dm_recursive(uchar *serialized, uchar *optr, size_t *retsize);\nextern void lwgeom_force4d_recursive(uchar *serialized, uchar *optr, size_t *retsize);\nextern double distance2d_pt_pt(POINT2D *p1, POINT2D *p2);\nextern double distance2d_pt_seg(POINT2D *p, POINT2D *A, POINT2D *B);\nextern double distance2d_seg_seg(POINT2D *A, POINT2D *B, POINT2D *C, POINT2D *D);\nextern double distance2d_pt_ptarray(POINT2D *p, POINTARRAY *pa);\nextern double distance2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2);\nextern int pt_in_ring_2d(POINT2D *p, POINTARRAY *ring);\nextern int pt_in_poly_2d(POINT2D *p, LWPOLY *poly);\nextern double distance2d_ptarray_poly(POINTARRAY *pa, LWPOLY *poly);\nextern double distance2d_point_point(LWPOINT *point1, LWPOINT *point2);\nextern double distance2d_point_line(LWPOINT *point, LWLINE *line);\nextern double distance2d_line_line(LWLINE *line1, LWLINE *line2);\nextern double distance2d_point_poly(LWPOINT *point, LWPOLY *poly);\nextern double distance2d_poly_poly(LWPOLY *poly1, LWPOLY *poly2);\nextern double distance2d_line_poly(LWLINE *line, LWPOLY *poly);\nextern int azimuth_pt_pt(POINT2D *p1, POINT2D *p2, double *ret);\nextern double lwgeom_mindistance2d_recursive(uchar *lw1, uchar *lw2);\nextern double lwgeom_mindistance2d_recursive_tolerance(uchar *lw1, uchar *lw2, double tolerance);\nextern int lwgeom_pt_inside_circle(POINT2D *p, double cx, double cy, double rad);\nextern int32 lwgeom_npoints(uchar *serialized);\nextern char ptarray_isccw(const POINTARRAY *pa);\nextern void lwgeom_reverse(LWGEOM *lwgeom);\nextern void lwline_reverse(LWLINE *line);\nextern void lwpoly_reverse(LWPOLY *poly);\nextern void lwpoly_forceRHR(LWPOLY *poly);\nextern void lwgeom_forceRHR(LWGEOM *lwgeom);\nextern char *lwgeom_summary(LWGEOM *lwgeom, int offset);\nextern const char *lwgeom_typename(int type);\nextern int ptarray_compute_box2d_p(const POINTARRAY *pa, BOX2DFLOAT4 *result);\nextern BOX2DFLOAT4 *ptarray_compute_box2d(const POINTARRAY *pa);\nextern int lwpoint_compute_box2d_p(LWPOINT *point, BOX2DFLOAT4 *box);\nextern int lwline_compute_box2d_p(LWLINE *line, BOX2DFLOAT4 *box);\nextern int lwpoly_compute_box2d_p(LWPOLY *poly, BOX2DFLOAT4 *box);\nextern int lwcollection_compute_box2d_p(LWCOLLECTION *col, BOX2DFLOAT4 *box);\nextern int lwcircstring_compute_box2d_p(LWCIRCSTRING *curve, BOX2DFLOAT4 *box);\nextern BOX2DFLOAT4 *lwgeom_compute_box2d(LWGEOM *lwgeom);\n\nextern void interpolate_point4d(POINT4D *A, POINT4D *B, POINT4D *I, double F);\n\n/* return alloced memory */\nextern BOX2DFLOAT4 *box2d_union(BOX2DFLOAT4 *b1, BOX2DFLOAT4 *b2);\n\n/* args may overlap ! */\nextern int box2d_union_p(BOX2DFLOAT4 *b1, BOX2DFLOAT4 *b2, BOX2DFLOAT4 *ubox);\nextern int lwgeom_compute_box2d_p(LWGEOM *lwgeom, BOX2DFLOAT4 *box);\nvoid lwgeom_longitude_shift(LWGEOM *lwgeom);\n\n/* Is lwgeom1 geometrically equal to lwgeom2 ? */\nchar lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2);\nchar ptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2);\nchar lwpoint_same(const LWPOINT *p1, const LWPOINT *p2);\nchar lwline_same(const LWLINE *p1, const LWLINE *p2);\nchar lwpoly_same(const LWPOLY *p1, const LWPOLY *p2);\nchar lwcollection_same(const LWCOLLECTION *p1, const LWCOLLECTION *p2);\n\n/*\n * Add 'what' to 'to' at position 'where'.\n * where=0 == prepend\n * where=-1 == append\n * Mix of dimensions is not allowed (TODO: allow it?).\n * Returns a newly allocated LWGEOM (with NO BBOX)\n */\nextern LWGEOM *lwgeom_add(const LWGEOM *to, uint32 where, const LWGEOM *what);\n\nLWGEOM *lwpoint_add(const LWPOINT *to, uint32 where, const LWGEOM *what);\nLWGEOM *lwline_add(const LWLINE *to, uint32 where, const LWGEOM *what);\nLWGEOM *lwpoly_add(const LWPOLY *to, uint32 where, const LWGEOM *what);\nLWGEOM *lwmpoly_add(const LWMPOLY *to, uint32 where, const LWGEOM *what);\nLWGEOM *lwmline_add(const LWMLINE *to, uint32 where, const LWGEOM *what);\nLWGEOM *lwmpoint_add(const LWMPOINT *to, uint32 where, const LWGEOM *what);\nLWGEOM *lwcollection_add(const LWCOLLECTION *to, uint32 where, const LWGEOM *what);\nLWGEOM *lwcompound_add(const LWCOMPOUND *to, uint32 where, const LWGEOM *what);\nLWGEOM *lwcurvepoly_add(const LWCURVEPOLY *to, uint32 where, const LWGEOM *what);\nLWGEOM *lwmcurve_add(const LWMCURVE *to, uint32 where, const LWGEOM *what);\nLWGEOM *lwmsurface_add(const LWMSURFACE *to, uint32 where, const LWGEOM *what);\nLWGEOM *lwcircstring_add(const LWCIRCSTRING *to, uint32 where, const LWGEOM *what);\n\n/*\n * Clone an LWGEOM\n * pointarray are not copied.\n * BBOXes are copied \n */\nextern LWGEOM *lwgeom_clone(const LWGEOM *lwgeom);\nextern LWPOINT *lwpoint_clone(const LWPOINT *lwgeom);\nextern LWLINE *lwline_clone(const LWLINE *lwgeom);\nextern LWPOLY *lwpoly_clone(const LWPOLY *lwgeom);\nextern LWCOLLECTION *lwcollection_clone(const LWCOLLECTION *lwgeom);\nextern LWCIRCSTRING *lwcircstring_clone(const LWCIRCSTRING *curve);\nextern BOX2DFLOAT4 *box2d_clone(const BOX2DFLOAT4 *lwgeom);\nextern POINTARRAY *ptarray_clone(const POINTARRAY *ptarray);\n\n/*\n * Geometry constructors\n * Take ownership of arguments\n */\nextern LWPOINT  *lwpoint_construct(int SRID, BOX2DFLOAT4 *bbox,\n\tPOINTARRAY *point);\nextern LWLINE *lwline_construct(int SRID, BOX2DFLOAT4 *bbox,\n\tPOINTARRAY *points);\n\n/*\n * Construct a new LWPOLY.  arrays (points/points per ring) will NOT be copied\n * use SRID=-1 for unknown SRID (will have 8bit type's S = 0)\n */\nextern LWPOLY *lwpoly_construct(int SRID, BOX2DFLOAT4 *bbox,\n\tunsigned int nrings, POINTARRAY **points);\n\nextern LWCOLLECTION *lwcollection_construct(unsigned int type, int SRID,\n\tBOX2DFLOAT4 *bbox, unsigned int ngeoms, LWGEOM **geoms);\nextern LWCOLLECTION *lwcollection_construct_empty(int SRID,\n\tchar hasZ, char hasM);\n\n/*\n * Construct a new LWCIRCSTRING.  arrays (points/points per ring) will NOT be copied\n * use SRID=-1 for unknown SRID (will have 8bit type's S = 0)\n */\nextern LWCIRCSTRING *lwcircstring_construct(int SRID, BOX2DFLOAT4 *bbox, POINTARRAY *points);\n\n/* Other constructors */\nextern LWPOINT *make_lwpoint2d(int SRID, double x, double y);\nextern LWPOINT *make_lwpoint3dz(int SRID, double x, double y, double z);\nextern LWPOINT *make_lwpoint3dm(int SRID, double x, double y, double m);\nextern LWPOINT *make_lwpoint4d(int SRID, double x, double y, double z, double m);\nextern LWLINE *lwline_from_lwpointarray(int SRID, unsigned int npoints, LWPOINT **points);\nextern LWLINE *lwline_from_lwmpoint(int SRID, LWMPOINT *mpoint);\nextern LWLINE *lwline_addpoint(LWLINE *line, LWPOINT *point, unsigned int where);\nextern LWLINE *lwline_removepoint(LWLINE *line, unsigned int which);\nextern void lwline_setPoint4d(LWLINE *line, unsigned int which, POINT4D *newpoint);\nextern LWPOLY *lwpoly_from_lwlines(const LWLINE *shell, unsigned int nholes, const LWLINE **holes);\n\n/* Return a char string with ASCII versionf of type flags */\nextern const char *lwgeom_typeflags(uchar type);\n\n/* Construct an empty pointarray */\nextern POINTARRAY *ptarray_construct(char hasz, char hasm, unsigned int npoints);\n\n/*\n * extern POINTARRAY *ptarray_construct2d(uint32 npoints, const POINT2D *pts);\n * extern POINTARRAY *ptarray_construct3dz(uint32 npoints, const POINT3DZ *pts);\n * extern POINTARRAY *ptarray_construct3dm(uint32 npoints, const POINT3DM *pts);\n * extern POINTARRAY *ptarray_construct4d(uint32 npoints, const POINT4D *pts);\n */\n\nextern POINTARRAY *ptarray_addPoint(POINTARRAY *pa, uchar *p, size_t pdims,\n\tunsigned int where);\nextern POINTARRAY *ptarray_removePoint(POINTARRAY *pa, unsigned int where);\n\nextern int ptarray_isclosed2d(const POINTARRAY *pa);\n\nextern void ptarray_longitude_shift(POINTARRAY *pa);\n\nextern int32 lwgeom_nrings_recursive(uchar *serialized);\nextern void ptarray_reverse(POINTARRAY *pa);\nextern POINTARRAY *ptarray_substring(POINTARRAY *, double, double);\nextern double ptarray_locate_point(POINTARRAY *, POINT2D *);\nextern void closest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret);\n\n/*\n * Ensure every segment is at most 'dist' long.\n * Returned LWGEOM might is unchanged if a POINT.\n */\nextern LWGEOM *lwgeom_segmentize2d(LWGEOM *line, double dist);\nextern POINTARRAY *ptarray_segmentize2d(POINTARRAY *ipa, double dist);\nextern LWLINE *lwline_segmentize2d(LWLINE *line, double dist);\nextern LWPOLY *lwpoly_segmentize2d(LWPOLY *line, double dist);\nextern LWCOLLECTION *lwcollection_segmentize2d(LWCOLLECTION *coll, double dist);\n\nextern uchar parse_hex(char *str);\nextern void deparse_hex(uchar str, char *result);\n\n/* Parser check flags */\n#define PARSER_CHECK_MINPOINTS  1\n#define PARSER_CHECK_ODD        2\n#define PARSER_CHECK_CLOSURE    4\n\n#define PARSER_CHECK_NONE   0\n#define PARSER_CHECK_ALL\t(PARSER_CHECK_MINPOINTS | PARSER_CHECK_ODD | PARSER_CHECK_CLOSURE)\n\n/*\n * Parser result structure: returns the result of attempting to convert (E)WKT/(E)WKB to LWGEOM \n */\ntypedef struct struct_lwgeom_parser_result\n{\n\tconst char *wkinput;\t\t/* Copy of pointer to input WKT/WKB */\n\tuchar *serialized_lwgeom;\t/* Pointer to serialized LWGEOM */\n\tint size;\t\t\t/* Size of serialized LWGEOM in bytes */\n\tconst char *message;\t\t/* Error/warning message */\n\tint errlocation;\t\t/* Location of error */\n} LWGEOM_PARSER_RESULT;\n\n/*\n * Parser error messages (these must match the message array in lwgparse.c)\n */\n#define PARSER_ERROR_MOREPOINTS     1\n#define PARSER_ERROR_ODDPOINTS      2\t\n#define PARSER_ERROR_UNCLOSED       3 \n#define PARSER_ERROR_MIXDIMS        4\t\n#define PARSER_ERROR_INVALIDGEOM    5\n#define PARSER_ERROR_INVALIDWKBTYPE 6\n\n\n/*\n * Unparser result structure: returns the result of attempting to convert LWGEOM to (E)WKT/(E)WKB \n */\ntypedef struct struct_lwgeom_unparser_result\n{\n\tuchar *serialized_lwgeom;\t/* Copy of pointer to input serialized LWGEOM */\n\tchar *wkoutput;\t\t\t/* Pointer to WKT or WKB output */\n\tint size;\t\t\t/* Size of serialized LWGEOM in bytes */\n\tconst char *message;\t\t/* Error/warning message */\n\tint errlocation;\t\t/* Location of error */\n} LWGEOM_UNPARSER_RESULT;\n\n/*\n * Unparser error messages (these must match the message array in lwgunparse.c)\n */\n#define UNPARSER_ERROR_MOREPOINTS \t1\n#define UNPARSER_ERROR_ODDPOINTS\t2\t\n#define UNPARSER_ERROR_UNCLOSED\t\t3 \n\n\n/* Parser access routines */\nextern char *lwgeom_to_ewkt(LWGEOM *lwgeom, int flags);\nextern char *lwgeom_to_hexwkb(LWGEOM *lwgeom, int flags, unsigned int byteorder);\nextern LWGEOM *lwgeom_from_ewkb(uchar *ewkb, int flags, size_t ewkblen);\nextern LWGEOM *lwgeom_from_ewkt(char *ewkt, int flags);\nextern uchar *lwgeom_to_ewkb(LWGEOM *lwgeom, int flags, char byteorder, size_t *ewkblen);\n\nextern int serialized_lwgeom_to_ewkt(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar *serialized, int flags);\nextern int serialized_lwgeom_from_ewkt(LWGEOM_PARSER_RESULT *lwg_parser_result, char *wkt_input, int flags);\nextern int serialized_lwgeom_to_hexwkb(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar *serialized, int flags, unsigned int byteorder);\nextern int serialized_lwgeom_from_hexwkb(LWGEOM_PARSER_RESULT *lwg_parser_result, char *hexwkb_input, int flags);\nextern int serialized_lwgeom_to_ewkb(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar *serialized, int flags, unsigned int byteorder);\n\nextern void *lwalloc(size_t size);\nextern void *lwrealloc(void *mem, size_t size);\nextern void lwfree(void *mem);\n\n/* Utilities */\nextern void trim_trailing_zeros(char *num);\nextern char *lwmessage_truncate(char *str, int startpos, int endpos, int maxlength, int truncdirection);\n\n/* Machine endianness */\n#define XDR 0\n#define NDR 1\nextern char getMachineEndian(void);\n\nvoid errorIfSRIDMismatch(int srid1, int srid2);\n\n\n/*******************************************************************************\n * SQLMM internal functions - TODO: Move into separate header files\n ******************************************************************************/\n\nuint32 has_arc(LWGEOM *geom);\ndouble lwcircle_center(POINT4D *p1, POINT4D *p2, POINT4D *p3, POINT4D **result);\nLWGEOM *lwgeom_segmentize(LWGEOM *geom, uint32 perQuad);\nLWGEOM *lwgeom_desegmentize(LWGEOM *geom);\nextern double lwgeom_curvepolygon_area(LWCURVEPOLY *curvepoly);\ndouble lwcircle_center(POINT4D *p1, POINT4D *p2, POINT4D *p3, POINT4D **result);\n\n#endif /* !defined _LIBLWGEOM_H  */\n\n"
  },
  {
    "path": "src/liblwgeom/lwalgorithm.c",
    "content": "/**********************************************************************\n * $Id: lwalgorithm.c 3812 2009-03-09 14:36:15Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2008 Paul Ramsey\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n *\n **********************************************************************/\n\n#include \"lwalgorithm.h\"\n\n\n/*\n** lw_segment_side()\n**\n** Return < 0.0 if point Q is left of segment P\n** Return > 0.0 if point Q is right of segment P\n** Return = 0.0 if point Q in on segment P\n*/\ndouble lw_segment_side(POINT2D *p1, POINT2D *p2, POINT2D *q)\n{\n\treturn ( (q->x - p1->x) * (p2->y - p1->y) - (p2->x - p1->x) * (q->y - p1->y) );\n}\n\nint lw_segment_envelope_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q2)\n{\n\tdouble minq=LW_MIN(q1.x,q2.x);\n\tdouble maxq=LW_MAX(q1.x,q2.x);\n\tdouble minp=LW_MIN(p1.x,p2.x);\n\tdouble maxp=LW_MAX(p1.x,p2.x);\n\n\tif (minp>maxq || maxp<minq)\n\t\treturn LW_FALSE;\n\n\tminq=LW_MIN(q1.y,q2.y);\n\tmaxq=LW_MAX(q1.y,q2.y);\n\tminp=LW_MIN(p1.y,p2.y);\n\tmaxp=LW_MAX(p1.y,p2.y);\n\n\tif (minp>maxq || maxp<minq)\n\t\treturn LW_FALSE;\n\n\treturn LW_TRUE;\n}\n\n/*\n** lw_segment_intersects()\n**\n** Returns one of\n**\tSEG_ERROR = -1,\n**\tSEG_NO_INTERSECTION = 0,\n**\tSEG_COLINEAR = 1,\n**\tSEG_CROSS_LEFT = 2,\n**\tSEG_CROSS_RIGHT = 3,\n**\tSEG_TOUCH_LEFT = 4,\n**\tSEG_TOUCH_RIGHT = 5\n*/\nint lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2)\n{\n\n\tdouble pq1, pq2, qp1, qp2;\n\n\t/* No envelope interaction => we are done. */\n\tif (!lw_segment_envelope_intersects(*p1, *p2, *q1, *p2))\n\t{\n\t\treturn SEG_NO_INTERSECTION;\n\t}\n\n\t/* Are the start and end points of q on the same side of p? */\n\tpq1=lw_segment_side(p1,p2,q1);\n\tpq2=lw_segment_side(p1,p2,q2);\n\tif ((pq1>0 && pq2>0) || (pq1<0 && pq2<0))\n\t{\n\t\treturn SEG_NO_INTERSECTION;\n\t}\n\n\t/* Are the start and end points of p on the same side of q? */\n\tqp1=lw_segment_side(q1,q2,p1);\n\tqp2=lw_segment_side(q1,q2,p2);\n\tif ((qp1>0 && qp2>0) || (qp1<0 && qp2<0))\n\t{\n\t\treturn SEG_NO_INTERSECTION;\n\t}\n\n\t/* Nobody is on one side or another? Must be colinear. */\n\tif (pq1 == 0.0 && pq2 == 0.0 && qp1 == 0.0 && qp2 == 0.0)\n\t{\n\t\treturn SEG_COLINEAR;\n\t}\n\n\t/*\n\t** When one end-point touches, the sidedness is determined by the \n\t** location of the other end-point.\n\t*/\n\tif ( pq2 == 0.0 )\n\t{\n\t\tif ( pq1 < 0.0 )\n\t\t\treturn SEG_TOUCH_LEFT;\n\t\telse\n\t\t\treturn SEG_TOUCH_RIGHT;\n\t}\n\tif ( pq1 == 0.0 )\n\t{\n\t\tif ( pq2 < 0.0 )\n\t\t\treturn SEG_TOUCH_LEFT;\n\t\telse\n\t\t\treturn SEG_TOUCH_RIGHT;\n\t}\n\n\t/* The segments cross, what direction is the crossing? */\n\tif ( pq1 < pq2 )\n\t\treturn SEG_CROSS_RIGHT;\n\telse\n\t\treturn SEG_CROSS_LEFT;\n\n\t/* This should never happen! */\n\treturn SEG_ERROR;\n\n}\n\n/*\n** lwline_crossing_direction()\n**\n** Returns one of\n**   LINE_NO_CROSS = 0\n**   LINE_CROSS_LEFT = -1\n**   LINE_CROSS_RIGHT = 1\n**   LINE_MULTICROSS_END_LEFT = -2\n**   LINE_MULTICROSS_END_RIGHT = 2\n**   LINE_MULTICROSS_END_SAME_FIRST_LEFT = -3\n**   LINE_MULTICROSS_END_SAME_FIRST_RIGHT = 3\n**\n*/\nint lwline_crossing_direction(LWLINE *l1, LWLINE *l2)\n{\n\n\tint i = 0, j = 0, rv = 0;\n\tPOINT2D *p1;\n\tPOINT2D *p2;\n\tPOINT2D *q1;\n\tPOINT2D *q2;\n\tPOINTARRAY *pa1;\n\tPOINTARRAY *pa2;\n\tint cross_left = 0;\n\tint cross_right = 0;\n\tint first_cross = 0;\n\tint final_cross = 0;\n\tint this_cross = 0;\n\tint vertex_touch = -1;\n\tint vertex_touch_type = 0;\n\n\tpa1 = (POINTARRAY*)l1->points;\n\tpa2 = (POINTARRAY*)l2->points;\n\n\tp1 = lwalloc(sizeof(POINT2D));\n\tp2 = lwalloc(sizeof(POINT2D));\n\tq1 = lwalloc(sizeof(POINT2D));\n\tq2 = lwalloc(sizeof(POINT2D));\n\n\t/* One-point lines can't intersect (and shouldn't exist). */\n\tif ( pa1->npoints < 2 || pa2->npoints < 2 )\n\t\treturn LINE_NO_CROSS;\n\n\tLWDEBUGF(4, \"lineCrossingDirection: l1 = %s\", lwgeom_to_ewkt((LWGEOM*)l1,0));\n\tLWDEBUGF(4, \"lineCrossingDirection: l2 = %s\", lwgeom_to_ewkt((LWGEOM*)l2,0));\n\n\tfor ( i = 1; i < pa2->npoints; i++ )\n\t{\n\n\t\trv = getPoint2d_p(pa2, i-1, q1);\n\t\trv = getPoint2d_p(pa2, i, q2);\n\n\t\tfor ( j = 1; j < pa1->npoints; j++ )\n\t\t{\n\n\t\t\trv = getPoint2d_p(pa1, j-1, p1);\n\t\t\trv = getPoint2d_p(pa1, j, p2);\n\n\t\t\tLWDEBUGF(4, \"lineCrossingDirection: i=%d, j=%d\", i, j);\n\n\t\t\tthis_cross = lw_segment_intersects(p1, p2, q1, q2);\n\n\t\t\tif ( ! first_cross && this_cross )\n\t\t\t\tfirst_cross = this_cross;\n\t\t\tif ( this_cross )\n\t\t\t\tfinal_cross = this_cross;\n\n\t\t\tif ( this_cross == SEG_CROSS_LEFT )\n\t\t\t{\n\t\t\t\tcross_left++;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif ( this_cross == SEG_CROSS_RIGHT )\n\t\t\t{\n\t\t\t\tcross_right++;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t** Crossing at a co-linearity can be turned into crossing at\n\t\t\t** a vertex by pulling the original touch point forward along\n\t\t\t** the co-linearity.\n\t\t\t*/\n\t\t\tif ( this_cross == SEG_COLINEAR && vertex_touch == (i-1) )\n\t\t\t{\n\t\t\t\tvertex_touch = i;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t** Crossing-at-vertex will cause four segment touch interactions, two at\n\t\t\t** j-1 and two at j. We avoid incrementing our cross count by ignoring the\n\t\t\t** second pair.\n\t\t\t*/\n\t\t\tif ( this_cross == SEG_TOUCH_LEFT )\n\t\t\t{\n\t\t\t\tif ( vertex_touch == (i-1) && vertex_touch_type == SEG_TOUCH_RIGHT )\n\t\t\t\t{\n\t\t\t\t\tcross_left++;\n\t\t\t\t\tvertex_touch = -1;\n\t\t\t\t\tvertex_touch_type = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tvertex_touch = i;\n\t\t\t\t\tvertex_touch_type = this_cross;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( this_cross == SEG_TOUCH_RIGHT )\n\t\t\t{\n\t\t\t\tif ( vertex_touch == (i-1) && vertex_touch_type == SEG_TOUCH_LEFT )\n\t\t\t\t{\n\t\t\t\t\tcross_right++;\n\t\t\t\t\tvertex_touch = -1;\n\t\t\t\t\tvertex_touch_type = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tvertex_touch = i;\n\t\t\t\t\tvertex_touch_type = this_cross;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t** TODO Handle co-linear cases. \n\t\t\t*/\n\n\t\t\tLWDEBUGF(4, \"lineCrossingDirection: this_cross=%d, vertex_touch=%d, vertex_touch_type=%d\", this_cross, vertex_touch, vertex_touch_type);\n\n\t\t}\n\n\t}\n\n\tLWDEBUGF(4, \"first_cross=%d, final_cross=%d, cross_left=%d, cross_right=%d\", first_cross, final_cross, cross_left, cross_right);\n\n\tlwfree(p1);\n\tlwfree(p2);\n\tlwfree(q1);\n\tlwfree(q2);\n\n\tif ( !cross_left && !cross_right )\n\t\treturn LINE_NO_CROSS;\n\n\tif ( !cross_left && cross_right == 1 )\n\t\treturn LINE_CROSS_RIGHT;\n\n\tif ( !cross_right && cross_left == 1 )\n\t\treturn LINE_CROSS_LEFT;\n\n\tif ( cross_left - cross_right == 1 )\n\t\treturn LINE_MULTICROSS_END_LEFT;\n\n\tif ( cross_left - cross_right == -1 )\n\t\treturn LINE_MULTICROSS_END_RIGHT;\n\n\tif ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_LEFT )\n\t\treturn LINE_MULTICROSS_END_SAME_FIRST_LEFT;\n\n\tif ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_RIGHT )\n\t\treturn LINE_MULTICROSS_END_SAME_FIRST_RIGHT;\n\n\tif ( cross_left - cross_right == 0 && first_cross == SEG_TOUCH_LEFT )\n\t\treturn LINE_MULTICROSS_END_SAME_FIRST_RIGHT;\n\n\tif ( cross_left - cross_right == 0 && first_cross == SEG_TOUCH_RIGHT )\n\t\treturn LINE_MULTICROSS_END_SAME_FIRST_LEFT;\n\n\treturn LINE_NO_CROSS;\n\n}\n\n/*\n** lwpoint_get_ordinate(point, ordinate) => double\n*/\ndouble lwpoint_get_ordinate(const POINT4D *p, int ordinate)\n{\n\tif ( ! p )\n\t{\n\t\tlwerror(\"Null input geometry.\");\n\t\treturn 0.0;\n\t}\n\n\tif ( ordinate > 3 || ordinate < 0 )\n\t{\n\t\tlwerror(\"Cannot extract ordinate %d.\", ordinate);\n\t\treturn 0.0;\n\t}\n\n\tif ( ordinate == 3 )\n\t\treturn p->m;\n\tif ( ordinate == 2 )\n\t\treturn p->z;\n\tif ( ordinate == 1 )\n\t\treturn p->y;\n\n\treturn p->x;\n\n}\nvoid lwpoint_set_ordinate(POINT4D *p, int ordinate, double value)\n{\n\tif ( ! p )\n\t{\n\t\tlwerror(\"Null input geometry.\");\n\t\treturn;\n\t}\n\n\tif ( ordinate > 3 || ordinate < 0 )\n\t{\n\t\tlwerror(\"Cannot extract ordinate %d.\", ordinate);\n\t\treturn;\n\t}\n\t\n\tLWDEBUGF(4, \"    setting ordinate %d to %g\", ordinate, value);\n\n\tswitch ( ordinate )\n\t{\n\tcase 3:\n\t\tp->m = value;\n\t\treturn;\n\tcase 2:\n\t\tp->z = value;\n\t\treturn;\n\tcase 1:\n\t\tp->y = value;\n\t\treturn;\n\tcase 0:\n\t\tp->x = value;\n\t\treturn;\n\t}\n}\n\n\nint lwpoint_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int ndims, int ordinate, double interpolation_value)\n{\n\tdouble p1_value = lwpoint_get_ordinate(p1, ordinate);\n\tdouble p2_value = lwpoint_get_ordinate(p2, ordinate);\n\tdouble proportion;\n\tint i = 0;\n\n\tif ( ordinate < 0 || ordinate >= ndims )\n\t{\n\t\tlwerror(\"Ordinate (%d) is not within ndims (%d).\", ordinate, ndims);\n\t\treturn 0;\n\t}\n\n\tif ( FP_MIN(p1_value, p2_value) > interpolation_value ||\n\t        FP_MAX(p1_value, p2_value) < interpolation_value )\n\t{\n\t\tlwerror(\"Cannot interpolate to a value (%g) not between the input points (%g, %g).\", interpolation_value, p1_value, p2_value);\n\t\treturn 0;\n\t}\n\n\tproportion = fabs((interpolation_value - p1_value) / (p2_value - p1_value));\n\n\tfor ( i = 0; i < ndims; i++ )\n\t{\n\t\tdouble newordinate = 0.0;\n\t\tp1_value = lwpoint_get_ordinate(p1, i);\n\t\tp2_value = lwpoint_get_ordinate(p2, i);\n\t\tnewordinate = p1_value + proportion * (p2_value - p1_value);\n\t\tlwpoint_set_ordinate(p, i, newordinate);\n\t\tLWDEBUGF(4, \"   clip ordinate(%d) p1_value(%g) p2_value(%g) proportion(%g) newordinate(%g) \", i, p1_value, p2_value, proportion, newordinate );\n\t}\n\n\treturn 1;\n}\n\nLWCOLLECTION *lwmline_clip_to_ordinate_range(LWMLINE *mline, int ordinate, double from, double to)\n{\n\tLWCOLLECTION *lwgeom_out = NULL;\n\n\tif ( ! mline )\n\t{\n\t\tlwerror(\"Null input geometry.\");\n\t\treturn NULL;\n\t}\n\n\tif ( mline->ngeoms == 1)\n\t{\n\t\tlwgeom_out = lwline_clip_to_ordinate_range(mline->geoms[0], ordinate, from, to);\n\t}\n\telse\n\t{\n\t\tLWCOLLECTION *col;\n\t\tchar hasz = TYPE_HASZ(mline->type);\n\t\tchar hasm = TYPE_HASM(mline->type);\n\t\tchar hassrid = TYPE_HASSRID(mline->type);\n\t\tint i, j;\n\t\tchar homogeneous = 1;\n\t\tsize_t geoms_size = 0;\n\t\tlwgeom_out = lwcollection_construct_empty(mline->SRID, hasz, hasm);\n\t\tlwgeom_out->type = lwgeom_makeType(hasz, hasm, hassrid, MULTILINETYPE);\n\t\tfor ( i = 0; i < mline->ngeoms; i ++ )\n\t\t{\n\t\t\tcol = lwline_clip_to_ordinate_range(mline->geoms[i], ordinate, from, to);\n\t\t\tif ( col )\n\t\t\t{ /* Something was left after the clip. */\n\t\t\t\tif ( lwgeom_out->ngeoms + col->ngeoms > geoms_size )\n\t\t\t\t{\n\t\t\t\t\tgeoms_size += 16;\n\t\t\t\t\tif ( lwgeom_out->geoms )\n\t\t\t\t\t{\n\t\t\t\t\t\tlwgeom_out->geoms = lwrealloc(lwgeom_out->geoms, geoms_size * sizeof(LWGEOM*));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tlwgeom_out->geoms = lwalloc(geoms_size * sizeof(LWGEOM*));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor ( j = 0; j < col->ngeoms; j++ )\n\t\t\t\t{\n\t\t\t\t\tlwgeom_out->geoms[lwgeom_out->ngeoms] = col->geoms[j];\n\t\t\t\t\tlwgeom_out->ngeoms++;\n\t\t\t\t}\n\t\t\t\tif ( TYPE_GETTYPE(col->type) != TYPE_GETTYPE(mline->type) )\n\t\t\t\t{\n\t\t\t\t\thomogeneous = 0;\n\t\t\t\t}\n\t\t\t\t/* Shallow free the struct, leaving the geoms behind. */\n\t\t\t\tif ( col->bbox ) lwfree(col->bbox);\n\t\t\t\tlwfree(col);\n\t\t\t}\n\t\t}\n\t\tlwgeom_drop_bbox((LWGEOM*)lwgeom_out);\n\t\tlwgeom_add_bbox((LWGEOM*)lwgeom_out);\n\t\tif ( ! homogeneous )\n\t\t{\n\t\t\tlwgeom_out->type = lwgeom_makeType(hasz, hasm, hassrid, COLLECTIONTYPE);\n\t\t}\n\t}\n\n\tif ( ! lwgeom_out || lwgeom_out->ngeoms == 0 ) /* Nothing left after clip. */\n\t{\n\t\treturn NULL;\n\t}\n\n\treturn lwgeom_out;\n\n}\n\n\n/*\n** lwline_clip_to_ordinate_range(line, ordinate, from, to) => lwmline\n**\n** Take in a LINESTRING and return a MULTILINESTRING of those portions of the\n** LINESTRING between the from/to range for the specified ordinate (XYZM)\n*/\nLWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double from, double to)\n{\n\n\tPOINTARRAY *pa_in = NULL;\n\tLWCOLLECTION *lwgeom_out = NULL;\n\tPOINTARRAY *pa_out = NULL;\n\tDYNPTARRAY *dp = NULL;\n\tint i, rv;\n\tint added_last_point = 0;\n\tPOINT4D *p = NULL, *q = NULL, *r = NULL;\n\tdouble ordinate_value_p = 0.0, ordinate_value_q = 0.0;\n\tchar hasz = TYPE_HASZ(line->type);\n\tchar hasm = TYPE_HASM(line->type);\n\tchar dims = TYPE_NDIMS(line->type);\n\tchar hassrid = TYPE_HASSRID(line->type);\n\n\tLWDEBUGF(4, \"hassrid = %d\", hassrid);\n\n\t/* Null input, nothing we can do. */\n\tif ( ! line )\n\t{\n\t\tlwerror(\"Null input geometry.\");\n\t\treturn NULL;\n\t}\n\n\t/* Ensure 'from' is less than 'to'. */\n\tif ( to < from )\n\t{\n\t\tdouble t = from;\n\t\tfrom = to;\n\t\tto = t;\n\t}\n\n\tLWDEBUGF(4, \"from = %g, to = %g, ordinate = %d\", from, to, ordinate);\n\tLWDEBUGF(4, \"%s\", lwgeom_to_ewkt((LWGEOM*)line, PARSER_CHECK_NONE));\n\n\t/* Asking for an ordinate we don't have. Error. */\n\tif ( ordinate >= dims )\n\t{\n\t\tlwerror(\"Cannot clip on ordinate %d in a %d-d geometry.\", ordinate, dims);\n\t\treturn NULL;\n\t}\n\n\t/* Prepare our working point objects. */\n\tp = lwalloc(sizeof(POINT4D));\n\tq = lwalloc(sizeof(POINT4D));\n\tr = lwalloc(sizeof(POINT4D));\n\n\t/* Construct a collection to hold our outputs. */\n\tlwgeom_out = lwalloc(sizeof(LWCOLLECTION));\n\tlwgeom_out->type = lwgeom_makeType(hasz, hasm, hassrid, MULTILINETYPE);\n\tif (hassrid)\n\t\tlwgeom_out->SRID = line->SRID;\n\telse\n\t\tlwgeom_out->SRID = -1;\n\tlwgeom_out->bbox = NULL;\n\tlwgeom_out->ngeoms = 0;\n\tlwgeom_out->geoms = NULL;\n\n\tpa_in = (POINTARRAY*)line->points;\n\n\tfor ( i = 0; i < pa_in->npoints; i++ )\n\t{\n\t\tLWDEBUGF(4, \"Point #%d\", i);\n\t\tif ( i > 0 )\n\t\t{\n\t\t\tq->x = p->x;\n\t\t\tq->y = p->y;\n\t\t\tq->z = p->z;\n\t\t\tq->m = p->m;\n\t\t\tordinate_value_q = ordinate_value_p;\n\t\t}\n\t\trv = getPoint4d_p(pa_in, i, p);\n\t\tordinate_value_p = lwpoint_get_ordinate(p, ordinate);\n\t\tLWDEBUGF(4, \" ordinate_value_p %g (current)\", ordinate_value_p);\n\t\tLWDEBUGF(4, \" ordinate_value_q %g (previous)\", ordinate_value_q);\n\n\t\t/* Is this point inside the ordinate range? Yes. */\n\t\tif ( ordinate_value_p >= from && ordinate_value_p <= to )\n\t\t{\n\t\t\tLWDEBUGF(4, \" inside ordinate range (%g, %g)\", from, to);\n\n\t\t\tif ( ! added_last_point )\n\t\t\t{\n\t\t\t\tLWDEBUG(4,\"  new ptarray required\");\n\t\t\t\t/* We didn't add the previous point, so this is a new segment.\n\t\t\t\t*  Make a new point array. */\n\t\t\t\tif ( dp ) lwfree(dp);\n\t\t\t\tdp = dynptarray_create(64, line->type);\n\n\t\t\t\t/* We're transiting into the range so add an interpolated\n\t\t\t\t*  point at the range boundary. \n\t\t\t\t*  If we're on a boundary and crossing from the far side, \n\t\t\t\t*  we also need an interpolated point. */\n\t\t\t\tif ( i > 0 && ( /* Don't try to interpolate if this is the first point */\n\t\t\t\t            ( ordinate_value_p > from && ordinate_value_p < to ) || /* Inside */\n\t\t\t\t            ( ordinate_value_p == from && ordinate_value_q > to ) || /* Hopping from above */\n\t\t\t\t            ( ordinate_value_p == to && ordinate_value_q < from ) ) ) /* Hopping from below */\n\t\t\t\t{\n\t\t\t\t\tdouble interpolation_value;\n\t\t\t\t\t(ordinate_value_q > to) ? (interpolation_value = to) : (interpolation_value = from);\n\t\t\t\t\trv = lwpoint_interpolate(q, p, r, dims, ordinate, interpolation_value);\n\t\t\t\t\trv = dynptarray_addPoint4d(dp, r, 0);\n\t\t\t\t\tLWDEBUGF(4, \" interpolating between (%g, %g) with interpolation point (%g)\", ordinate_value_q, ordinate_value_p, interpolation_value);\n\t\t\t\t}\n\t\t\t}\n\t\t\t/* Add the current vertex to the point array. */\n\t\t\trv = dynptarray_addPoint4d(dp, p, 0);\n\t\t\tif ( ordinate_value_p == from || ordinate_value_p == to )\n\t\t\t{\n\t\t\t\tadded_last_point = 2; /* Added on boundary. */\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tadded_last_point = 1; /* Added inside range. */\n\t\t\t}\n\t\t}\n\t\t/* Is this point inside the ordinate range? No. */\n\t\telse\n\t\t{\n\t\t\tLWDEBUGF(4, \"  added_last_point (%d)\", added_last_point);\n\t\t\tif ( added_last_point == 1 )\n\t\t\t{\n\t\t\t\t/* We're transiting out of the range, so add an interpolated point\n\t\t\t\t*  to the point array at the range boundary. */\n\t\t\t\tdouble interpolation_value;\n\t\t\t\t(ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from);\n\t\t\t\trv = lwpoint_interpolate(q, p, r, dims, ordinate, interpolation_value);\n\t\t\t\trv = dynptarray_addPoint4d(dp, r, 0);\n\t\t\t\tLWDEBUGF(4, \" interpolating between (%g, %g) with interpolation point (%g)\", ordinate_value_q, ordinate_value_p, interpolation_value);\n\t\t\t}\n\t\t\telse if ( added_last_point == 2 )\n\t\t\t{\n\t\t\t\t/* We're out and the last point was on the boundary.\n\t\t\t\t*  If the last point was the near boundary, nothing to do.\n\t\t\t\t*  If it was the far boundary, we need an interpolated point. */\n\t\t\t\tif ( from != to && (\n\t\t\t\t     (ordinate_value_q == from && ordinate_value_p > from) ||\n\t\t\t\t     (ordinate_value_q == to && ordinate_value_p < to) ) )\n\t\t\t\t{\n\t\t\t\t\tdouble interpolation_value;\n\t\t\t\t\t(ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from);\n\t\t\t\t\trv = lwpoint_interpolate(q, p, r, dims, ordinate, interpolation_value);\n\t\t\t\t\trv = dynptarray_addPoint4d(dp, r, 0);\n\t\t\t\t\tLWDEBUGF(4, \" interpolating between (%g, %g) with interpolation point (%g)\", ordinate_value_q, ordinate_value_p, interpolation_value);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( i && ordinate_value_q < from && ordinate_value_p > to )\n\t\t\t{\n\t\t\t\t/* We just hopped over the whole range, from bottom to top,\n\t\t\t\t*  so we need to add *two* interpolated points! */\n\t\t\t\tpa_out = ptarray_construct(hasz, hasm, 2);\n\t\t\t\t/* Interpolate lower point. */\n\t\t\t\trv = lwpoint_interpolate(p, q, r, dims, ordinate, from);\n\t\t\t\tsetPoint4d(pa_out, 0, r);\n\t\t\t\t/* Interpolate upper point. */\n\t\t\t\trv = lwpoint_interpolate(p, q, r, dims, ordinate, to);\n\t\t\t\tsetPoint4d(pa_out, 1, r);\n\t\t\t}\n\t\t\telse if ( i && ordinate_value_q > to && ordinate_value_p < from )\n\t\t\t{\n\t\t\t\t/* We just hopped over the whole range, from top to bottom,\n\t\t\t\t*  so we need to add *two* interpolated points! */\n\t\t\t\tpa_out = ptarray_construct(hasz, hasm, 2);\n\t\t\t\t/* Interpolate upper point. */\n\t\t\t\trv = lwpoint_interpolate(p, q, r, dims, ordinate, to);\n\t\t\t\tsetPoint4d(pa_out, 0, r);\n\t\t\t\t/* Interpolate lower point. */\n\t\t\t\trv = lwpoint_interpolate(p, q, r, dims, ordinate, from);\n\t\t\t\tsetPoint4d(pa_out, 1, r);\n\t\t\t}\n\t\t\t/* We have an extant point-array, save it out to a multi-line. */\n\t\t\tif ( dp || pa_out )\n\t\t\t{\n\t\t\t\tLWGEOM *oline;\n\t\t\t\tLWDEBUG(4, \"saving pointarray to multi-line (1)\");\n\t\t\t\tif ( dp )\n\t\t\t\t{\n\t\t\t\t\t/* Only one point, so we have to make an lwpoint to hold this\n\t\t\t\t\t*  and set the overall output type to a generic collection. */\n\t\t\t\t\tif ( dp->pa->npoints == 1 )\n\t\t\t\t\t{\n\t\t\t\t\t\toline = (LWGEOM*)lwpoint_construct(line->SRID, NULL, dp->pa);\n\t\t\t\t\t\toline->type = lwgeom_makeType(hasz, hasm, hassrid, POINTTYPE);\n\t\t\t\t\t\tlwgeom_out->type = lwgeom_makeType(hasz, hasm, hassrid, COLLECTIONTYPE);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\toline = (LWGEOM*)lwline_construct(line->SRID, NULL, dp->pa);\n\t\t\t\t\t\toline->type = lwgeom_makeType(hasz, hasm, hassrid, LINETYPE);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\toline = (LWGEOM*)lwline_construct(line->SRID, NULL, pa_out);\n\t\t\t\t}\n\t\t\t\tlwgeom_out->ngeoms++;\n\t\t\t\tif ( lwgeom_out->geoms ) /* We can't just realloc, since repalloc chokes on a starting null ptr. */\n\t\t\t\t{\n\t\t\t\t\tlwgeom_out->geoms = lwrealloc(lwgeom_out->geoms, sizeof(LWGEOM*) * lwgeom_out->ngeoms);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tlwgeom_out->geoms = lwalloc(sizeof(LWGEOM*) * lwgeom_out->ngeoms);\n\t\t\t\t}\n\t\t\t\tlwgeom_out->geoms[lwgeom_out->ngeoms - 1] = oline;\n\t\t\t\tlwgeom_drop_bbox((LWGEOM*)lwgeom_out);\n\t\t\t\tlwgeom_add_bbox((LWGEOM*)lwgeom_out);\n\t\t\t\tif ( dp ) lwfree(dp);\n\t\t\t\tdp = NULL;\n\t\t\t\tif ( pa_out ) pa_out = NULL;\n\t\t\t}\n\t\t\tadded_last_point = 0;\n\n\t\t}\n\t}\n\n\t/* Still some points left to be saved out. */\n\tif ( dp && dp->pa->npoints > 0 )\n\t{\n\t\tLWGEOM *oline;\n\t\tLWDEBUG(4, \"saving pointarray to multi-line (2)\");\n\t\tLWDEBUGF(4, \"dp->pa->npoints == %d\", dp->pa->npoints);\n\t\tLWDEBUGF(4, \"lwgeom_out->ngeoms == %d\", lwgeom_out->ngeoms);\n\t\t\n\t\tif ( dp->pa->npoints == 1 )\n\t\t{\n\t\t\toline = (LWGEOM*)lwpoint_construct(line->SRID, NULL, dp->pa);\n\t\t\toline->type = lwgeom_makeType(hasz, hasm, hassrid, POINTTYPE);\n\t\t\tlwgeom_out->type = lwgeom_makeType(hasz, hasm, hassrid, COLLECTIONTYPE);\n\t\t}\n\t\telse\n\t\t{\n\t\t\toline = (LWGEOM*)lwline_construct(line->SRID, NULL, dp->pa);\n\t\t\toline->type = lwgeom_makeType(hasz, hasm, hassrid, LINETYPE);\n\t\t}\n\t\t\n\t\tlwgeom_out->ngeoms++;\n\t\tif ( lwgeom_out->geoms ) /* We can't just realloc, since repalloc chokes on a starting null ptr. */\n\t\t{\n\t\t\tlwgeom_out->geoms = lwrealloc(lwgeom_out->geoms, sizeof(LWGEOM*) * lwgeom_out->ngeoms);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlwgeom_out->geoms = lwalloc(sizeof(LWGEOM*) * lwgeom_out->ngeoms);\n\t\t}\n\t\tlwgeom_out->geoms[lwgeom_out->ngeoms - 1] = oline;\n\t\tlwgeom_drop_bbox((LWGEOM*)lwgeom_out);\n\t\tlwgeom_add_bbox((LWGEOM*)lwgeom_out);\n\t\tif ( dp ) lwfree(dp);\n\t\tdp = NULL;\n\t}\n\n\tlwfree(p);\n\tlwfree(q);\n\tlwfree(r);\n\n\tif ( lwgeom_out->ngeoms > 0 )\n\t\treturn lwgeom_out;\n\n\treturn NULL;\n\n}\n\nstatic char *base32 = \"0123456789bcdefghjkmnpqrstuvwxyz\";\n\n/*\n** Calculate the geohash, iterating downwards and gaining precision.\n** From geohash-native.c, (c) 2008 David Troy <dave@roundhousetech.com>\n** Released under the MIT License.\n*/\nchar *geohash_point(double longitude, double latitude, int precision)\n{   \n\tint is_even=1, i=0;\n\tdouble lat[2], lon[2], mid;\n\tchar bits[] = {16,8,4,2,1};\n\tint bit=0, ch=0;\n\tchar *geohash = NULL;\n\n\tgeohash = lwalloc(precision + 1);\n\n\tlat[0] = -90.0;  lat[1] = 90.0;\n\tlon[0] = -180.0; lon[1] = 180.0;\n\n\twhile (i < precision) \n\t{\n\t\tif (is_even) \n\t\t{\n\t\t\tmid = (lon[0] + lon[1]) / 2;\n\t\t\tif (longitude > mid) \n\t\t\t{\n\t\t\t\tch |= bits[bit];\n\t\t\t\tlon[0] = mid;\n\t\t\t} \n\t\t\telse\n\t\t\t{\n\t\t\t\tlon[1] = mid;\n\t\t\t}\n\t\t} \n\t\telse \n\t\t{\n\t\t\tmid = (lat[0] + lat[1]) / 2;\n\t\t\tif (latitude > mid) \n\t\t\t{\n\t\t\t\tch |= bits[bit];\n\t\t\t\tlat[0] = mid;\n\t\t\t} \n\t\t\telse\n\t\t\t{\n\t\t\t\tlat[1] = mid;\n\t\t\t}\n\t\t}\n\n\t\tis_even = !is_even;\n\t\tif (bit < 4)\n\t\t{\n\t\t\tbit++;\n\t\t}\n\t\telse \n\t\t{\n\t\t\tgeohash[i++] = base32[ch];\n\t\t\tbit = 0;\n\t\t\tch = 0;\n\t\t}\n\t}\n\tgeohash[i] = 0;\n\treturn geohash;\n}\n\nint lwgeom_geohash_precision(BOX3D bbox, BOX3D *bounds)\n{\n\tdouble minx, miny, maxx, maxy;\n\tdouble latmax, latmin, lonmax, lonmin;\n\tdouble lonwidth, latwidth;\n\tdouble latmaxadjust, lonmaxadjust, latminadjust, lonminadjust;\n\tint precision = 0;\n\t\n\t/* Get the bounding box, return error if things don't work out. */\n\tminx = bbox.xmin;\n\tminy = bbox.ymin;\n\tmaxx = bbox.xmax;\n\tmaxy = bbox.ymax;\n\n\tif( minx == maxx && miny == maxy )\n\t{\n\t\t/* It's a point. Doubles have 51 bits of precision. \n\t\t** 2 * 51 / 5 == 20 */\n\t\treturn 20;\n\t}\n\n\tlonmin = -180.0;\n\tlatmin = -90.0;\n\tlonmax = 180.0;\n\tlatmax = 90.0;\n\n\t/* Shrink a world bounding box until one of the edges interferes with the\n\t** bounds of our rectangle. */\n\twhile( 1 ) \n\t{\n\t\tlonwidth = lonmax - lonmin;\n\t\tlatwidth = latmax - latmin;\n\t\tlatmaxadjust = lonmaxadjust = latminadjust = lonminadjust = 0.0;\n\n\t\tif( minx > lonmin + lonwidth / 2.0 ) \n\t\t{\n\t\t\tlonminadjust = lonwidth / 2.0;\n\t\t}\n\t\telse if ( maxx < lonmax - lonwidth / 2.0 ) \n\t\t{\n\t\t\tlonmaxadjust = -1 * lonwidth / 2.0;\n\t\t}\n\t\tif( miny > latmin + latwidth / 2.0 ) \n\t\t{\n\t\t\tlatminadjust = latwidth / 2.0;\n\t\t}\n\t\telse if (maxy < latmax - latwidth / 2.0 ) \n\t\t{\n\t\t\tlatmaxadjust = -1 * latwidth / 2.0;\n\t\t}\n\t\t/* Only adjust if adjustments are legal (we haven't crossed any edges). */\n\t\tif ( (lonminadjust || lonmaxadjust) && (latminadjust || latmaxadjust ) )\n\t\t{\n\t\t\tlatmin += latminadjust;\n\t\t\tlonmin += lonminadjust;\n\t\t\tlatmax += latmaxadjust;\n\t\t\tlonmax += lonmaxadjust;\n            /* Each adjustment cycle corresponds to 2 bits of storage in the \n\t        ** geohash.\t*/\n\t        precision += 2;\n\t\t}\n\t\telse \n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\t/* Save the edges of our bounds, in case someone cares later. */\n    bounds->xmin = lonmin;\n    bounds->xmax = lonmax;\n    bounds->ymin = latmin;\n    bounds->ymax = latmax;\n\n\t/* Each geohash character (base32) can contain 5 bits of information. \n\t** We are returning the precision in characters, so here we divide. */\n\treturn precision / 5;\n}\n\n\n/*\n** Return a geohash string for the geometry. <http://geohash.org>\n** Where the precision is non-positive, calculate a precision based on the \n** bounds of the feature. Big features have loose precision.\n** Small features have tight precision.\n*/\nchar *lwgeom_geohash(const LWGEOM *lwgeom, int precision) \n{\n\tBOX3D *bbox = NULL;\n    BOX3D precision_bounds;\n\tdouble lat, lon;\n\t\n\tbbox = lwgeom_compute_box3d(lwgeom);\n\tif( ! bbox ) return NULL;\n\t\n\t/* Return error if we are being fed something outside our working bounds */\n\tif ( bbox->xmin < -180 || bbox->ymin < -90 || bbox->xmax > 180 || bbox->ymax > 90 )\n\t{\n\t\tlwerror(\"Geohash requires inputs in decimal degrees.\");\n\t\tlwfree(bbox);\n\t\treturn NULL;\n\t}\n\n\t/* What is the center of our geometry bounds? We'll use that to \n\t** approximate location. */\n\tlon = bbox->xmin + (bbox->xmax - bbox->xmin) / 2;\n\tlat = bbox->ymin + (bbox->ymax - bbox->ymin) / 2;\n\n\tif ( precision <= 0 ) \n\t{\n\t    precision = lwgeom_geohash_precision(*bbox, &precision_bounds);\n    }\n\t\n\tlwfree(bbox);\n\n\t/* \n\t** Return the geohash of the center, with a precision determined by the\n\t** extent of the bounds. \n\t** Possible change: return the point at the center of the precision bounds?\n\t*/\n\treturn geohash_point(lon, lat, precision);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "src/liblwgeom/lwalgorithm.h",
    "content": "/**********************************************************************\n * $Id: lwalgorithm.h 3688 2009-02-11 21:48:13Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2008 Paul Ramsey\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <math.h>\n#include \"liblwgeom.h\"\n\nenum CG_SEGMENT_INTERSECTION_TYPE { \n\tSEG_ERROR = -1,\n\tSEG_NO_INTERSECTION = 0, \n\tSEG_COLINEAR = 1, \n\tSEG_CROSS_LEFT = 2, \n\tSEG_CROSS_RIGHT = 3, \n\tSEG_TOUCH_LEFT = 4, \n\tSEG_TOUCH_RIGHT = 5\n};\n\ndouble lw_segment_side(POINT2D *p1, POINT2D *p2, POINT2D *q);\nint lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2);\nint lw_segment_envelope_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q2);\n\n\nenum CG_LINE_CROSS_TYPE {\n\tLINE_NO_CROSS = 0,\n\tLINE_CROSS_LEFT = -1,\n\tLINE_CROSS_RIGHT = 1,\n\tLINE_MULTICROSS_END_LEFT = -2,\n\tLINE_MULTICROSS_END_RIGHT = 2,\n\tLINE_MULTICROSS_END_SAME_FIRST_LEFT = -3,\n\tLINE_MULTICROSS_END_SAME_FIRST_RIGHT = 3\n};\n\nint lwline_crossing_direction(LWLINE *l1, LWLINE *l2);\n\ndouble lwpoint_get_ordinate(const POINT4D *p, int ordinate);\nvoid lwpoint_set_ordinate(POINT4D *p, int ordinate, double value);\nint lwpoint_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int ndims, int ordinate, double interpolation_value);\nLWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double from, double to);\nLWCOLLECTION *lwmline_clip_to_ordinate_range(LWMLINE *mline, int ordinate, double from, double to);\n\nint lwgeom_geohash_precision(BOX3D bbox, BOX3D *bounds);\nchar *lwgeom_geohash(const LWGEOM *lwgeom, int precision);\nchar *geohash_point(double longitude, double latitude, int precision);\n\n"
  },
  {
    "path": "src/liblwgeom/lwcircstring.c",
    "content": "/**********************************************************************\n * $Id: lwcircstring.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n/* basic LWCIRCSTRING functions */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n#include \"liblwgeom.h\"\n\nBOX3D *lwcircle_compute_box3d(POINT4D *p1, POINT4D *p2, POINT4D *p3);\nvoid printLWCIRCSTRING(LWCIRCSTRING *curve);\nvoid lwcircstring_reverse(LWCIRCSTRING *curve);\nLWCIRCSTRING *lwcircstring_segmentize2d(LWCIRCSTRING *curve, double dist);\nchar lwcircstring_same(const LWCIRCSTRING *me, const LWCIRCSTRING *you);\nLWCIRCSTRING *lwcircstring_from_lwpointarray(int SRID, unsigned int npoints, LWPOINT **points);\nLWCIRCSTRING *lwcircstring_from_lwmpoint(int SRID, LWMPOINT *mpoint);\nLWCIRCSTRING *lwcircstring_addpoint(LWCIRCSTRING *curve, LWPOINT *point, unsigned int where);\nLWCIRCSTRING *lwcircstring_removepoint(LWCIRCSTRING *curve, unsigned int index);\nvoid lwcircstring_setPoint4d(LWCIRCSTRING *curve, unsigned int index, POINT4D *newpoint);\n\n\n\n#ifndef MAXFLOAT\n  #define MAXFLOAT      3.402823466e+38F\n#endif\n\n/*\n * Construct a new LWCIRCSTRING.  points will *NOT* be copied\n * use SRID=-1 for unknown SRID (will have 8bit type's S = 0)\n */\nLWCIRCSTRING *\nlwcircstring_construct(int SRID, BOX2DFLOAT4 *bbox, POINTARRAY *points)\n{\n        LWCIRCSTRING *result;\n        \n\t/*\n         * The first arc requires three points.  Each additional\n         * arc requires two more points.  Thus the minimum point count\n         * is three, and the count must be odd.\n         */\n        if(points->npoints % 2 != 1 || points->npoints < 3) \n        {\n                lwerror(\"lwcircstring_construct: invalid point count %d\", points->npoints);\n                return NULL;\n        }\n        \n        result = (LWCIRCSTRING*) lwalloc(sizeof(LWCIRCSTRING));\n\n        result->type = lwgeom_makeType_full(\n                TYPE_HASZ(points->dims),\n                TYPE_HASM(points->dims),\n                (SRID!=-1), CIRCSTRINGTYPE, 0);\n        result->SRID = SRID;\n        result->points = points;\n        result->bbox = bbox;\n         \n        return result;\n}\n\n/*\n * given the LWGEOM serialized form (or a point into a multi* one)\n * construct a proper LWCIRCSTRING.\n * serialized_form should point to the 8bit type format (with type = 8)\n * See serialized form doc\n */\nLWCIRCSTRING *\nlwcircstring_deserialize(uchar *serialized_form)\n{\n        uchar type;\n        LWCIRCSTRING *result;\n        uchar *loc=NULL;\n        uint32 npoints;\n        POINTARRAY *pa;\n\n        type = (uchar)serialized_form[0];\n        if(lwgeom_getType(type) != CIRCSTRINGTYPE)\n        {\n                lwerror(\"lwcircstring_deserialize: attempt to deserialize a circularstring which is really a %s\", lwgeom_typename(type));\n                return NULL;\n        }\n\n        result = (LWCIRCSTRING*) lwalloc(sizeof(LWCIRCSTRING));\n        result->type = type;\n\n        loc = serialized_form + 1;\n\n        if(lwgeom_hasBBOX(type))\n        {\n                LWDEBUG(3, \"lwcircstring_deserialize: input has bbox\");\n\n                result->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n                memcpy(result->bbox, loc, sizeof(BOX2DFLOAT4));\n                loc += sizeof(BOX2DFLOAT4);               \n         }\n         else\n         {\n                LWDEBUG(3, \"lwcircstring_deserialize: input lacks bbox\");           \n               \n                result->bbox = NULL;\n         }\n\n         if(lwgeom_hasSRID(type))\n         {\n                LWDEBUG(3, \"lwcircstring_deserialize: input has srid\");\n\n                result->SRID = lw_get_int32(loc);               \n                loc += 4; /* type + SRID */\n         }\n         else\n         {\n                LWDEBUG(3, \"lwcircstring_deserialize: input lacks srid\");\n\n                result->SRID = -1;                \n         }\n\n         /* we've read the type (1 byte) and SRID (4 bytes, if present) */\n\n         npoints = lw_get_uint32(loc);\n\n         LWDEBUGF(3, \"circstring npoints = %d\", npoints);\n         \n         loc += 4;\n         pa = pointArray_construct(loc, TYPE_HASZ(type), TYPE_HASM(type), npoints);\n         result->points = pa;\n         return result;\n}\n\n/*\n * convert this circularstring into its serialized form\n * result's first char will be the 8bit type. See serialized form doc\n */\nuchar *\nlwcircstring_serialize(LWCIRCSTRING *curve)\n{\n        size_t size, retsize;\n        uchar * result;\n\n        if(curve == NULL) {\n                lwerror(\"lwcircstring_serialize:: given null curve\");\n                return NULL;\n        }\n\n        size = lwcircstring_serialize_size(curve);\n        result = lwalloc(size);\n        lwcircstring_serialize_buf(curve, result, &retsize);\n        if(retsize != size)\n                lwerror(\"lwcircstring_serialize_size returned %d, ..serialize_buf returned %d\", size, retsize);\n        return result;\n}\n\n/*\n * convert this circularstring into its serialized form writing it into \n * the given buffer, and returning number of bytes written into \n * the given int pointer.\n * result's first char will be the 8bit type.  See serialized form doc\n */\nvoid lwcircstring_serialize_buf(LWCIRCSTRING *curve, uchar *buf, size_t *retsize)\n{\n        char hasSRID;\n        uchar *loc;\n        int ptsize;\n        size_t size;\n\n        LWDEBUGF(2, \"lwcircstring_serialize_buf(%p, %p, %p) called\",\n                curve, buf, retsize);\n\n        if(curve == NULL) \n        {\n                lwerror(\"lwcircstring_serialize:: given null curve\");\n                return;\n        }\n\n        if(TYPE_GETZM(curve->type) != TYPE_GETZM(curve->points->dims))\n        {\n                lwerror(\"Dimensions mismatch in lwcircstring\");\n                return;\n        }\n\n        ptsize = pointArray_ptsize(curve->points);\n\n        hasSRID = (curve->SRID != -1);\n\n        buf[0] = (uchar)lwgeom_makeType_full(\n                TYPE_HASZ(curve->type), TYPE_HASM(curve->type),\n                hasSRID, CIRCSTRINGTYPE, curve->bbox ? 1 : 0);\n        loc = buf+1;\n\n        LWDEBUGF(3, \"lwcircstring_serialize_buf added type (%d)\", curve->type);\n\n        if(curve->bbox)\n        {\n                memcpy(loc, curve->bbox, sizeof(BOX2DFLOAT4));\n                loc += sizeof(BOX2DFLOAT4);\n\n                LWDEBUG(3, \"lwcircstring_serialize_buf added BBOX\");\n        }                \n\n        if(hasSRID)\n        {\n                memcpy(loc, &curve->SRID, sizeof(int32));\n                loc += sizeof(int32);\n\n                LWDEBUG(3, \"lwcircstring_serialize_buf added SRID\");\n        }\n\n        memcpy(loc, &curve->points->npoints, sizeof(uint32));\n        loc += sizeof(uint32);\n\n        LWDEBUGF(3, \"lwcircstring_serialize_buf added npoints (%d)\",\n            curve->points->npoints);\n\n        /* copy in points */\n        size = curve->points->npoints * ptsize;\n        memcpy(loc, getPoint_internal(curve->points, 0), size);\n        loc += size;\n\n        LWDEBUGF(3, \"lwcircstring_serialize_buf copied serialized_pointlist (%d bytes)\",\n                ptsize * curve->points->npoints);        \n\n        if(retsize) *retsize = loc-buf;\n\n        LWDEBUGF(3, \"lwcircstring_serialize_buf returning (loc: %p, size: %d)\",\n                loc, loc-buf);\n}\n\n/* find length of this deserialized circularstring */\nsize_t\nlwcircstring_serialize_size(LWCIRCSTRING *curve)\n{\n        size_t size = 1; /* type */\n\n        LWDEBUG(2, \"lwcircstring_serialize_size called\");        \n\n        if(curve->SRID != -1) size += 4; /* SRID */\n        if(curve->bbox) size += sizeof(BOX2DFLOAT4);\n\n        size += 4; /* npoints */\n        size += pointArray_ptsize(curve->points) * curve->points->npoints;\n\n        LWDEBUGF(3, \"lwcircstring_serialize_size returning %d\", size);\n\n        return size;\n}\n\nBOX3D *\nlwcircle_compute_box3d(POINT4D *p1, POINT4D *p2, POINT4D *p3)\n{\n        double x1, x2, y1, y2, z1, z2;\n        double angle, radius, sweep;\n\t/* angles from center */\n        double a1, a2, a3;\n\t/* angles from center once a1 is rotated to zero */\n\tdouble r2, r3;\n        double xe = 0.0, ye = 0.0;\n        POINT4D *center;\n        int i;\n        BOX3D *box;\n\n        LWDEBUG(2, \"lwcircle_compute_box3d called.\");\n\n        center = lwalloc(sizeof(POINT4D));\n        radius = lwcircle_center(p1, p2, p3, &center);\n        if(radius < 0.0) return NULL;\n\n        /*\n        top = center->y + radius;\n        left = center->x - radius;\n\n        LWDEBUGF(3, \"lwcircle_compute_box3d: center (%.16f, %.16f)\", center->x, center->y);\n        */\n\n        x1 = MAXFLOAT;\n        x2 = -1 * MAXFLOAT;\n        y1 = MAXFLOAT;\n        y2 = -1 * MAXFLOAT;\n\n        a1 = atan2(p1->y - center->y, p1->x - center->x);\n        a2 = atan2(p2->y - center->y, p2->x - center->x);\n        a3 = atan2(p3->y - center->y, p3->x - center->x);\n\n\t/* Rotate a2 and a3 such that a1 = 0 */\n\tr2 = a2 - a1;\n\tr3 = a3 - a1;\n\n        /*\n         * There are six cases here I'm interested in\n         * Clockwise:\n         *   1. a1-a2 < 180 == r2 < 0 && (r3 > 0 || r3 < r2)\n         *   2. a1-a2 > 180 == r2 > 0 && (r3 > 0 && r3 < r2)\n         *   3. a1-a2 > 180 == r2 > 0 && (r3 > r2 || r3 < 0)\n         * Counter-clockwise:\n         *   4. a1-a2 < 180 == r2 > 0 && (r3 < 0 || r3 > r2)\n         *   5. a1-a2 > 180 == r2 < 0 && (r3 < 0 && r3 > r2)\n         *   6. a1-a2 > 180 == r2 < 0 && (r3 < r2 || r3 > 0)\n         * 3 and 6 are invalid cases where a3 is the midpoint.\n         * BBOX is fundamental, so these cannot error out and will instead\n         * calculate the sweep using a3 as the middle point.\n         */\n\n        /* clockwise 1 */\n        if(FP_LT(r2, 0) && (FP_GT(r3, 0) || FP_LT(r3, r2)))\n        {\n            sweep = (FP_GT(r3, 0)) ? (r3 - 2 * M_PI) : r3;\n        }\n        /* clockwise 2 */\n        else if(FP_GT(r2, 0) && FP_GT(r3, 0) && FP_LT(r3, r2))\n        {\n            sweep = (FP_GT(r3, 0)) ? (r3 - 2 * M_PI) : r3;\n        }\n        /* counter-clockwise 4 */\n        else if(FP_GT(r2, 0) && (FP_LT(r3, 0) || FP_GT(r3, r2)))\n        {\n            sweep = (FP_LT(r3, 0)) ? (r3 + 2 * M_PI) : r3;\n        }\n        /* counter-clockwise 5 */\n        else if(FP_LT(r2, 0) && FP_LT(r3, 0) && FP_GT(r3, r2))\n        {\n            sweep = (FP_LT(r3, 0)) ? (r3 + 2 * M_PI) : r3;\n        }\n        /* clockwise invalid 3 */\n        else if(FP_GT(r2, 0) && (FP_GT(r3, r2) || FP_LT(r3, 0)))\n        {\n            sweep = (FP_GT(r2, 0)) ? (r2 - 2 * M_PI) : r2;\n        }\n        /* clockwise invalid 6 */\n        else\n        {\n            sweep = (FP_LT(r2, 0)) ? (r2 + 2 * M_PI) : r2;\n        }\n\n        LWDEBUGF(3, \"a1 %.16f, a2 %.16f, a3 %.16f, sweep %.16f\", a1, a2, a3, sweep);\n\n        angle = 0.0;\n        for(i=0; i < 6; i++)\n        {\n                switch(i) {\n\t\t/* right extent */\n                case 0:\n                        angle = 0.0;\n                        xe = center->x + radius;\n                        ye = center->y;\n                        break;\n\t\t/* top extent */\n                case 1:\n                        angle = M_PI_2;\n                        xe = center->x;\n                        ye = center->y + radius;\n                        break;\n\t\t/* left extent */\n                case 2:\n                        angle = M_PI;\n                        xe = center->x - radius;\n                        ye = center->y;\n                        break;\n\t\t/* bottom extent */\n                case 3:\n                        angle = -1 * M_PI_2;\n                        xe = center->x;\n                        ye = center->y - radius;\n                        break;\n\t\t/* first point */\n                case 4:\n                        angle = a1;\n                        xe = p1->x;\n                        ye = p1->y;\n                        break;\n\t\t/* last point */\n                case 5:\n                        angle = a3;\n                        xe = p3->x;\n                        ye = p3->y;\n                        break;\n                }\n\t\t/* determine if the extents are outside the arc */\n                if(i < 4) \n                {\n\t\t    if(FP_GT(sweep, 0.0))\n\t\t    {\n\t\t        if(FP_LT(a3, a1))\n\t\t        {\n\t\t\t    if(FP_GT(angle, (a3 + 2 * M_PI)) || FP_LT(angle, a1)) continue;\n\t\t        }\n\t\t        else\n\t\t        {\n\t\t\t    if(FP_GT(angle, a3) || FP_LT(angle, a1)) continue;\n\t\t        }\n                    }\n\t\t    else\n\t\t    {\n\t\t        if(FP_GT(a3, a1))\n\t\t        {\n\t\t\t    if(FP_LT(angle, (a3 - 2 * M_PI)) || FP_GT(angle, a1)) continue;\n\t\t        }\n\t\t        else\n\t\t        {\n\t\t\t    if(FP_LT(angle, a3) || FP_GT(angle, a1)) continue;\n\t\t        }\n\t\t    }\n\t\t}\n\n                LWDEBUGF(3, \"lwcircle_compute_box3d: potential extreame %d (%.16f, %.16f)\", i, xe, ye);\n\n                x1 = (FP_LT(x1, xe)) ? x1 : xe;\n                y1 = (FP_LT(y1, ye)) ? y1 : ye;\n                x2 = (FP_GT(x2, xe)) ? x2 : xe;\n                y2 = (FP_GT(y2, ye)) ? y2 : ye;\n        }\n\n        LWDEBUGF(3, \"lwcircle_compute_box3d: extreames found (%.16f %.16f, %.16f %.16f)\", x1, y1, x2, y2);\n\n        /*\n        x1 = center->x + x1 * radius;\n        x2 = center->x + x2 * radius;\n        y1 = center->y + y1 * radius;\n        y2 = center->y + y2 * radius;\n        */\n        z1 = (FP_LT(p1->z, p2->z)) ? p1->z : p2->z;\n        z1 = (FP_LT(z1, p3->z)) ? z1 : p3->z;\n        z2 = (FP_GT(p1->z, p2->z)) ? p1->z : p2->z;\n        z2 = (FP_GT(z2, p3->z)) ? z2 : p3->z;\n\n        box = lwalloc(sizeof(BOX3D));\n        box->xmin = x1; box->xmax = x2;\n        box->ymin = y1; box->ymax = y2;\n        box->zmin = z1; box->zmax = z2;\n\n        lwfree(center);\n\n        return box;\n}\n\n/*\n * Find bounding box (standard one)\n * zmin=zmax=NO_Z_VALUE if 2d\n * TODO: This ignores curvature, which should be taken into account.\n */\nBOX3D *\nlwcircstring_compute_box3d(LWCIRCSTRING *curve)\n{\n        BOX3D *box, *tmp; \n        int i;\n        POINT4D *p1 = lwalloc(sizeof(POINT4D));\n        POINT4D *p2 = lwalloc(sizeof(POINT4D));\n        POINT4D *p3 = lwalloc(sizeof(POINT4D));\n\n        LWDEBUG(2, \"lwcircstring_compute_box3d called.\");\n\n        /* initialize box values */\n        box = lwalloc(sizeof(BOX3D));\n        box->xmin = MAXFLOAT; box->xmax = -1 * MAXFLOAT;\n        box->ymin = MAXFLOAT; box->ymax = -1 * MAXFLOAT;\n        box->zmin = MAXFLOAT; box->zmax = -1 * MAXFLOAT;\n        \n        for(i = 2; i < curve->points->npoints; i+=2)\n        {\n                getPoint4d_p(curve->points, i-2, p1);\n                getPoint4d_p(curve->points, i-1, p2);\n                getPoint4d_p(curve->points, i, p3);\n                tmp = lwcircle_compute_box3d(p1, p2, p3);\n                if(tmp == NULL) continue;\n                box->xmin = (box->xmin < tmp->xmin) ? box->xmin : tmp->xmin;\n                box->xmax = (box->xmax > tmp->xmax) ? box->xmax : tmp->xmax;\n                box->ymin = (box->ymin < tmp->ymin) ? box->ymin : tmp->ymin;\n                box->ymax = (box->ymax > tmp->ymax) ? box->ymax : tmp->ymax;\n                box->zmin = (box->zmin < tmp->zmin) ? box->zmin : tmp->zmin;\n                box->zmax = (box->zmax > tmp->zmax) ? box->zmax : tmp->zmax;\n\n                LWDEBUGF(4, \"circularstring %d x=(%.16f,%.16f) y=(%.16f,%.16f) z=(%.16f,%.16f)\", i/2, box->xmin, box->xmax, box->ymin, box->ymax, box->zmin, box->zmax);\n        }\n\n        \n        return box;\n}\n\nint\nlwcircstring_compute_box2d_p(LWCIRCSTRING *curve, BOX2DFLOAT4 *result)\n{\n        BOX3D *box = lwcircstring_compute_box3d(curve);\n        LWDEBUG(2, \"lwcircstring_compute_box2d_p called.\");\n\n        if(box == NULL) return 0;\n        box3d_to_box2df_p(box, result);\n        return 1;\n}\n\nvoid lwcircstring_free(LWCIRCSTRING *curve)\n{\n        lwfree(curve->points);\n        lwfree(curve);\n}\n\n/* find length of this serialized curve */\nsize_t\nlwgeom_size_circstring(const uchar *serialized_curve)\n{\n        int type = (uchar)serialized_curve[0];\n        uint32 result = 1; /* type */\n        const uchar *loc;\n        uint32 npoints;\n\n        LWDEBUG(2, \"lwgeom_size_circstring called\");\n\n        if(lwgeom_getType(type) != CIRCSTRINGTYPE)\n                lwerror(\"lwgeom_size_circstring::attempt to find the length of a non-circularstring\");\n\n        loc = serialized_curve + 1;\n        if(lwgeom_hasBBOX(type))\n        {\n                loc += sizeof(BOX2DFLOAT4);\n                result += sizeof(BOX2DFLOAT4);\n        }\n\n        if(lwgeom_hasSRID(type))\n        {\n                loc += 4; /* type + SRID */\n                result += 4;\n        }\n\n        /* we've read the type (1 byte) and SRID (4 bytes, if present) */\n        npoints = lw_get_uint32(loc);\n        result += sizeof(uint32); /* npoints */\n\n        result += TYPE_NDIMS(type) * sizeof(double) * npoints;\n\n        LWDEBUGF(3, \"lwgeom_size_circstring returning %d\", result);\n\n        return result;\n}\n\nvoid printLWCIRCSTRING(LWCIRCSTRING *curve)\n{\n        lwnotice(\"LWCIRCSTRING {\");\n        lwnotice(\"    ndims = %i\", (int)TYPE_NDIMS(curve->type));\n        lwnotice(\"    SRID = %i\", (int)curve->SRID);\n        printPA(curve->points);\n        lwnotice(\"}\");\n}\n\n/* Clone LWCIRCSTRING object.  POINTARRAY is not copied. */\nLWCIRCSTRING *\nlwcircstring_clone(const LWCIRCSTRING *g)\n{\n        LWCIRCSTRING *ret = lwalloc(sizeof(LWCIRCSTRING));\n        memcpy(ret, g, sizeof(LWCIRCSTRING));\n        if(g->bbox) ret->bbox = box2d_clone(g->bbox);\n        return ret;\n}\n\n/*\n * Add 'what' to this curve at position 'where'.\n * where=0 == prepend\n * where=-1 == append\n * Returns a MULTICURVE or a GEOMETRYCOLLECTION\n */\nLWGEOM *\nlwcircstring_add(const LWCIRCSTRING *to, uint32 where, const LWGEOM *what)\n{\n        LWCOLLECTION *col;\n        LWGEOM **geoms;\n        int newtype;\n        \n        if(where != -1 && where != 0)\n        {\n                lwerror(\"lwcurve_add only supports 0 or -1 as second argument %d\", where);\n                return NULL;\n        }\n\n        /* dimensions compatibility are checked by caller */\n\n        /* Construct geoms array */\n        geoms = lwalloc(sizeof(LWGEOM *)*2);\n        if(where == -1) /* append */\n        {\n                geoms[0] = lwgeom_clone((LWGEOM *)to);\n                geoms[1] = lwgeom_clone(what);\n        }\n        else /* prepend */\n        {\n                geoms[0] = lwgeom_clone(what);\n                geoms[1] = lwgeom_clone((LWGEOM *)to);\n        }\n        \n        /* reset SRID and wantbbox flag from component types */\n        geoms[0]->SRID = geoms[1]->SRID = -1;\n        TYPE_SETHASSRID(geoms[0]->type, 0);\n        TYPE_SETHASSRID(geoms[1]->type, 0);\n        TYPE_SETHASBBOX(geoms[0]->type, 0);\n        TYPE_SETHASBBOX(geoms[1]->type, 0);\n\n        /* Find appropriate geom type */\n        if(TYPE_GETTYPE(what->type) == CIRCSTRINGTYPE || TYPE_GETTYPE(what->type) == LINETYPE) newtype = MULTICURVETYPE;\n        else newtype = COLLECTIONTYPE;\n\n        col = lwcollection_construct(newtype, \n                to->SRID, NULL, \n                2, geoms);\n\n        return (LWGEOM *)col;\n}\n\nvoid lwcircstring_reverse(LWCIRCSTRING *curve)\n{\n        ptarray_reverse(curve->points);\n}\n\n/*\n * TODO: Invalid segmentization.  This should accomodate the curvature.\n */\nLWCIRCSTRING *\nlwcircstring_segmentize2d(LWCIRCSTRING *curve, double dist)\n{\n        return lwcircstring_construct(curve->SRID, NULL,\n                ptarray_segmentize2d(curve->points, dist));\n}\n                    \n/* check coordinate equality */\nchar\nlwcircstring_same(const LWCIRCSTRING *me, const LWCIRCSTRING *you)\n{\n        return ptarray_same(me->points, you->points);\n}\n\n/*\n * Construct a LWCIRCSTRING from an array of LWPOINTs\n * LWCIRCSTRING dimensions are large enough to host all input dimensions.\n */\nLWCIRCSTRING *\nlwcircstring_from_lwpointarray(int SRID, unsigned int npoints, LWPOINT **points)\n{\n        int zmflag=0;\n        unsigned int i;\n        POINTARRAY *pa;\n        uchar *newpoints, *ptr;\n        size_t ptsize, size;\n\n        /*\n         * Find output dimensions, check integrity\n         */\n        for(i = 0; i < npoints; i++)\n        {\n                if(TYPE_GETTYPE(points[i]->type) != POINTTYPE)\n                {\n                        lwerror(\"lwcurve_from_lwpointarray: invalid input type: %s\",\n                            lwgeom_typename(TYPE_GETTYPE(points[i]->type)));\n                        return NULL;\n                }\n                if(TYPE_HASZ(points[i]->type)) zmflag |= 2;\n                if(TYPE_HASM(points[i]->type)) zmflag |=1;\n                if(zmflag == 3) break;\n        }\n\n        if(zmflag == 0) ptsize = 2 * sizeof(double);\n        else if(zmflag == 3) ptsize = 4 * sizeof(double);\n        else ptsize = 3 * sizeof(double);\n\n        /*\n         * Allocate output points array\n         */\n        size = ptsize * npoints;\n        newpoints = lwalloc(size);\n        memset(newpoints, 0, size);\n\n        ptr = newpoints;\n        for(i = 0; i < npoints; i++)\n        {\n                size = pointArray_ptsize(points[i]->point);\n                memcpy(ptr, getPoint_internal(points[i]->point, 0), size);\n                ptr += ptsize;\n        }\n        pa = pointArray_construct(newpoints, zmflag&2, zmflag&1, npoints);\n\n        return lwcircstring_construct(SRID, NULL, pa);\n}\n\n/*\n * Construct a LWCIRCSTRING from a LWMPOINT\n */\nLWCIRCSTRING *\nlwcircstring_from_lwmpoint(int SRID, LWMPOINT *mpoint)\n{\n        unsigned int i;\n        POINTARRAY *pa;\n        char zmflag = TYPE_GETZM(mpoint->type);\n        size_t ptsize, size;\n        uchar *newpoints, *ptr;\n\n        if(zmflag == 0) ptsize = 2 * sizeof(double);\n        else if(zmflag == 3) ptsize = 4 * sizeof(double);\n        else ptsize = 3 * sizeof(double);\n\n        /* Allocate space for output points */\n        size = ptsize * mpoint->ngeoms;\n        newpoints = lwalloc(size);\n        memset(newpoints, 0, size);\n\n        ptr = newpoints;\n        for(i = 0; i < mpoint->ngeoms; i++)\n        {\n                memcpy(ptr,\n                        getPoint_internal(mpoint->geoms[i]->point, 0),\n                        ptsize);\n                ptr += ptsize;\n        }\n\n        pa = pointArray_construct(newpoints, zmflag&2, zmflag&1,\n                mpoint->ngeoms);\n\n        LWDEBUGF(3, \"lwcurve_from_lwmpoint: constructed pointarray for %d points, %d zmflag\", mpoint->ngeoms, zmflag);\n        \n        return lwcircstring_construct(SRID, NULL, pa);\n}\n\nLWCIRCSTRING *\nlwcircstring_addpoint(LWCIRCSTRING *curve, LWPOINT *point, unsigned int where)\n{\n        POINTARRAY *newpa;\n        LWCIRCSTRING *ret;\n\n        newpa = ptarray_addPoint(curve->points, \n                getPoint_internal(point->point, 0),\n                TYPE_NDIMS(point->type), where);\n        ret = lwcircstring_construct(curve->SRID, NULL, newpa);\n\n        return ret;\n}\n\nLWCIRCSTRING *\nlwcircstring_removepoint(LWCIRCSTRING *curve, unsigned int index)\n{\n        POINTARRAY *newpa;\n        LWCIRCSTRING *ret;\n\n        newpa = ptarray_removePoint(curve->points, index);\n        ret = lwcircstring_construct(curve->SRID, NULL, newpa);\n\n        return ret;\n}\n\n/*\n * Note: input will be changed, make sure you have permissions for this.\n * */\nvoid\nlwcircstring_setPoint4d(LWCIRCSTRING *curve, unsigned int index, POINT4D *newpoint)\n{\n        setPoint4d(curve->points, index, newpoint);\n}\n\n\n"
  },
  {
    "path": "src/liblwgeom/lwcollection.c",
    "content": "/**********************************************************************\n * $Id: lwcollection.c 3812 2009-03-09 14:36:15Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"liblwgeom.h\"\n\n\n#define CHECK_LWGEOM_ZM 1\n\nvoid\nlwcollection_release(LWCOLLECTION *lwcollection)\n{\n  lwgeom_release(lwcollection_as_lwgeom(lwcollection));\n}\n\n\nLWCOLLECTION *\nlwcollection_construct(unsigned int type, int SRID, BOX2DFLOAT4 *bbox,\n\tunsigned int ngeoms, LWGEOM **geoms)\n{\n\tLWCOLLECTION *ret;\n\tint hasz, hasm;\n#ifdef CHECK_LWGEOM_ZM\n\tchar zm;\n\tunsigned int i;\n#endif\n\n        LWDEBUGF(2, \"lwcollection_construct called with %d, %d, %p, %d, %p.\", type, SRID, bbox, ngeoms, geoms);\n\n\thasz = 0;\n\thasm = 0;\n\tif ( ngeoms > 0 )\n\t{\n\t\thasz = TYPE_HASZ(geoms[0]->type);\n\t\thasm = TYPE_HASM(geoms[0]->type);\n#ifdef CHECK_LWGEOM_ZM\n\t\tzm = TYPE_GETZM(geoms[0]->type);\n\n                LWDEBUGF(3, \"lwcollection_construct type[0]=%d\", geoms[0]->type);\n\n\t\tfor (i=1; i<ngeoms; i++)\n\t\t{\n                        LWDEBUGF(3, \"lwcollection_construct type=[%d]=%d\", i, geoms[i]->type);\n\n\t\t\tif ( zm != TYPE_GETZM(geoms[i]->type) )\n\t\t\t\tlwerror(\"lwcollection_construct: mixed dimension geometries: %d/%d\", zm, TYPE_GETZM(geoms[i]->type));\n\t\t}\n#endif\n\t}\n\n\n\tret = lwalloc(sizeof(LWCOLLECTION));\n\tret->type = lwgeom_makeType_full(hasz, hasm, (SRID!=-1),\n\t\ttype, 0);\n\tret->SRID = SRID;\n\tret->ngeoms = ngeoms;\n\tret->geoms = geoms;\n\tret->bbox = bbox;\n\n\treturn ret;\n}\n\nLWCOLLECTION *\nlwcollection_construct_empty(int SRID, char hasz, char hasm)\n{\n\tLWCOLLECTION *ret;\n\n\tret = lwalloc(sizeof(LWCOLLECTION));\n\tret->type = lwgeom_makeType_full(hasz, hasm, (SRID!=-1),\n\t\tCOLLECTIONTYPE, 0);\n\tret->SRID = SRID;\n\tret->ngeoms = 0;\n\tret->geoms = NULL;\n\tret->bbox = NULL;\n\n\treturn ret;\n}\n\n\nLWCOLLECTION *\nlwcollection_deserialize(uchar *srl)\n{\n\tLWCOLLECTION *result;\n\tLWGEOM_INSPECTED *insp;\n\tchar typefl = srl[0];\n\tint type = lwgeom_getType(typefl);\n\tint i;\n\n\tif ( type != COLLECTIONTYPE ) \n\t{\n\t\tlwerror(\"lwcollection_deserialize called on NON geometrycollection: %d\", type);\n\t\treturn NULL;\n\t}\n\n\tinsp = lwgeom_inspect(srl);\n\n\tresult = lwalloc(sizeof(LWCOLLECTION));\n\tresult->type = typefl;\n\tresult->SRID = insp->SRID;\n\tresult->ngeoms = insp->ngeometries;\n\n\tif (lwgeom_hasBBOX(srl[0]))\n\t{\n\t\tresult->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n\t\tmemcpy(result->bbox, srl+1, sizeof(BOX2DFLOAT4));\n\t}\n\telse result->bbox = NULL;\n\n\n\tif ( insp->ngeometries )\n\t{\n\t\tresult->geoms = lwalloc(sizeof(LWGEOM *)*insp->ngeometries);\n\t\tfor (i=0; i<insp->ngeometries; i++)\n\t\t{\n\t\t\tresult->geoms[i] =\n\t\t\t\tlwgeom_deserialize(insp->sub_geoms[i]);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nLWGEOM *\nlwcollection_getsubgeom(LWCOLLECTION *col, int gnum)\n{\n\treturn (LWGEOM *)col->geoms[gnum];\n}\n\n/* find serialized size of this collection */\nsize_t\nlwcollection_serialize_size(LWCOLLECTION *col)\n{\n\tsize_t size = 5; /* type + nsubgeoms */\n\tint i;\n\n\tif ( col->SRID != -1 ) size += 4; /* SRID */\n\tif ( col->bbox ) size += sizeof(BOX2DFLOAT4);\n\n\tLWDEBUGF(2, \"lwcollection_serialize_size[%p]: start size: %d\", col, size);\n\n\n\tfor (i=0; i<col->ngeoms; i++)\n\t{\n\t\tsize += lwgeom_serialize_size(col->geoms[i]);\n\n\t\tLWDEBUGF(3, \"lwcollection_serialize_size[%p]: with geom%d: %d\", col, i, size);\n\t}\n\n\tLWDEBUGF(3, \"lwcollection_serialize_size[%p]:  returning %d\", col, size);\n\n\treturn size; \n}\n\n/*\n * convert this collectoin into its serialize form writing it into\n * the given buffer, and returning number of bytes written into\n * the given int pointer.\n */\nvoid\nlwcollection_serialize_buf(LWCOLLECTION *coll, uchar *buf, size_t *retsize)\n{\n\tsize_t size=1; /* type  */\n\tsize_t subsize=0;\n\tchar hasSRID;\n\tuchar *loc;\n\tint i;\n\n\tLWDEBUGF(2, \"lwcollection_serialize_buf called (%s with %d elems)\",\n\t\tlwgeom_typename(TYPE_GETTYPE(coll->type)), coll->ngeoms);\n\n\thasSRID = (coll->SRID != -1);\n\n\tbuf[0] = lwgeom_makeType_full(\n\t\tTYPE_HASZ(coll->type), TYPE_HASM(coll->type),\n\t\thasSRID, TYPE_GETTYPE(coll->type), coll->bbox ? 1 : 0);\n\tloc = buf+1;\n\n\t/* Add BBOX if requested */\n\tif ( coll->bbox )\n\t{\n\t\tmemcpy(loc, coll->bbox, sizeof(BOX2DFLOAT4));\n\t\tsize += sizeof(BOX2DFLOAT4);\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t}\n\n\t/* Add SRID if requested */\n\tif (hasSRID)\n\t{\n\t\tmemcpy(loc, &coll->SRID, 4);\n\t\tsize += 4; \n\t\tloc += 4;\n\t}\n\n\t/* Write number of subgeoms */\n\tmemcpy(loc, &coll->ngeoms, 4);\n\tsize += 4;\n\tloc += 4;\n\n\t/* Serialize subgeoms */\n\tfor (i=0; i<coll->ngeoms; i++)\n\t{\n\t\tlwgeom_serialize_buf(coll->geoms[i], loc, &subsize);\n\t\tsize += subsize;\n\t\tloc += subsize;\n\t}\n\n\tif (retsize) *retsize = size;\n\n\tLWDEBUG(3, \"lwcollection_serialize_buf returning\");\n}\n\nint\nlwcollection_compute_box2d_p(LWCOLLECTION *col, BOX2DFLOAT4 *box)\n{\n\tBOX2DFLOAT4 boxbuf;\n\tuint32 i;\n\n\tif ( ! col->ngeoms ) return 0;\n\tif ( ! lwgeom_compute_box2d_p(col->geoms[0], box) ) return 0;\n\tfor (i=1; i<col->ngeoms; i++)\n\t{\n\t\tif ( ! lwgeom_compute_box2d_p(col->geoms[i], &boxbuf) )\n\t\t\treturn 0;\n\t\tif ( ! box2d_union_p(box, &boxbuf, box) ) return 0;\n\t}\n\treturn 1;\n}\n\n/*\n * Clone LWCOLLECTION object. POINTARRAY are not copied.\n * Bbox is cloned if present in input.\n */\nLWCOLLECTION *\nlwcollection_clone(const LWCOLLECTION *g)\n{\n\tuint32 i;\n\tLWCOLLECTION *ret = lwalloc(sizeof(LWCOLLECTION));\n\tmemcpy(ret, g, sizeof(LWCOLLECTION));\n\tif ( g->ngeoms > 0 )\n\t{\n\t\tret->geoms = lwalloc(sizeof(LWGEOM *)*g->ngeoms);\n\t\tfor (i=0; i<g->ngeoms; i++)\n\t\t{\n\t\t\tret->geoms[i] = lwgeom_clone(g->geoms[i]);\n\t\t}\n\t\tif ( g->bbox ) ret->bbox = box2d_clone(g->bbox);\n\t}\n\telse\n\t{\n\t\tret->bbox = NULL; /* empty collection */\n\t\tret->geoms = NULL;\n\t}\n\treturn ret;\n}\n\n/*\n * Add 'what' to this collection at position 'where'.\n * where=0 == prepend\n * where=-1 == append\n * Returns a GEOMETRYCOLLECTION\n */\nLWGEOM *\nlwcollection_add(const LWCOLLECTION *to, uint32 where, const LWGEOM *what)\n{\n\tLWCOLLECTION *col;\n\tLWGEOM **geoms;\n\tuint32 i;\n\n\tif ( where == -1 ) where = to->ngeoms;\n\telse if ( where < -1 || where > to->ngeoms )\n\t{\n\t\tlwerror(\"lwcollection_add: add position out of range %d..%d\",\n\t\t\t-1, to->ngeoms);\n\t\treturn NULL;\n\t}\n\n\t/* dimensions compatibility are checked by caller */\n\n\t/* Construct geoms array */\n\tgeoms = lwalloc(sizeof(LWGEOM *)*(to->ngeoms+1));\n\tfor (i=0; i<where; i++)\n\t{\n\t\tgeoms[i] = lwgeom_clone(to->geoms[i]);\n\t\tlwgeom_dropSRID(geoms[i]);\n\t\tlwgeom_drop_bbox(geoms[i]);\n\t}\n\tgeoms[where] = lwgeom_clone(what);\n\tlwgeom_dropSRID(geoms[where]);\n\tlwgeom_drop_bbox(geoms[where]);\n\tfor (i=where; i<to->ngeoms; i++)\n\t{\n\t\tgeoms[i+1] = lwgeom_clone(to->geoms[i]);\n\t\tlwgeom_dropSRID(geoms[i+1]);\n\t\tlwgeom_drop_bbox(geoms[i+1]);\n\t}\n\n\tcol = lwcollection_construct(COLLECTIONTYPE,\n\t\tto->SRID, NULL,\n\t\tto->ngeoms+1, geoms);\n\t\n\treturn (LWGEOM *)col;\n\n}\n\nLWCOLLECTION *\nlwcollection_segmentize2d(LWCOLLECTION *col, double dist)\n{\n\tunsigned int i;\n\tLWGEOM **newgeoms;\n\n\tif ( ! col->ngeoms ) return col;\n\n\tnewgeoms = lwalloc(sizeof(LWGEOM *)*col->ngeoms);\n\tfor (i=0; i<col->ngeoms; i++)\n\t\tnewgeoms[i] = lwgeom_segmentize2d(col->geoms[i], dist);\n\n\treturn lwcollection_construct(col->type, col->SRID, NULL,\n\t\tcol->ngeoms, newgeoms);\n}\n\n/* check for same geometry composition */\nchar\nlwcollection_same(const LWCOLLECTION *c1, const LWCOLLECTION *c2)\n{\n\tunsigned int i, j;\n\tunsigned int *hit;\n\n\tLWDEBUG(2, \"lwcollection_same called\");\n\n\tif ( TYPE_GETTYPE(c1->type) != TYPE_GETTYPE(c2->type) ) return 0;\n\tif ( c1->ngeoms != c2->ngeoms ) return 0;\n\n\thit = lwalloc(sizeof(unsigned int)*c1->ngeoms);\n\tmemset(hit, 0, sizeof(unsigned int)*c1->ngeoms);\n\n\tfor (i=0; i<c1->ngeoms; i++)\n\t{\n\t\tchar found=0;\n\t\tfor (j=0; j<c2->ngeoms; j++)\n\t\t{\n\t\t\tif ( hit[j] ) continue;\n\t\t\tif ( lwgeom_same(c1->geoms[i], c2->geoms[j]) )\n\t\t\t{\n\t\t\t\thit[j] = 1;\n\t\t\t\tfound=1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif ( ! found ) return 0;\n\t}\n\treturn 1;\n}\n\nint lwcollection_ngeoms(const LWCOLLECTION *col)\n{\n\tint i;\n\tint ngeoms = 0;\n\t\n\tif( ! col ) {\n\t\tlwerror(\"Null input geometry.\");\n\t\treturn 0;\n\t}\n\n\tfor( i = 0; i < col->ngeoms; i++ ) \n\t{\n\t\tif( col->geoms[i]) {\n\t\t\tswitch(TYPE_GETTYPE(col->geoms[i]->type)) {\n\t\t\t\tcase POINTTYPE:\n\t\t\t\tcase LINETYPE:\n\t\t\t\tcase CIRCSTRINGTYPE:\n\t\t\t\tcase POLYGONTYPE:\n\t\t\t\t\tngeoms += 1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase MULTIPOINTTYPE:\n\t\t\t\tcase MULTILINETYPE:\n\t\t\t\tcase MULTICURVETYPE:\n\t\t\t\tcase MULTIPOLYGONTYPE:\n\t\t\t\t\tngeoms += col->ngeoms;\n\t\t\t\t\tbreak;\n\t\t\t\tcase COLLECTIONTYPE:\n\t\t\t\t\tngeoms += lwcollection_ngeoms((LWCOLLECTION*)col->geoms[i]);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn ngeoms;\n}\n\n/* \n** Given a generic collection, return the \"simplest\" form. \n** eg: GEOMETRYCOLLECTION(MULTILINESTRING()) => MULTELINESTRING()\n**     GEOMETRYCOLLECTION(MULTILINESTRING(), MULTILINESTRING(), POINT()) => GEOMETRYCOLLECTION(MULTILINESTRING(), MULTIPOINT())\n**\n** In general, if the subcomponents are homogeneous, return a properly typed collection.\n** Otherwise, return a generic collection, with the subtypes in minimal typed collections. \nLWCOLLECTION *lwcollection_homogenize(const LWCOLLECTION *c1)\n{\nTODO: pramsey\n}\n*/\n\n/* \n** Given a generic collection, extract and return just the desired types.\nLWGEOM *lwcollection_extract(const LWCOLLECTION *col, char type)\n{\n\tLWGEOM **extracted_geoms;\n\textracted_geoms = lwalloc(sizeof(void*)*col->ngeoms);\n\textracted_curgeom = 0;\n\tchar reqtype = TYPE_GETTYPE(type);\n\tfor ( i = 0; i < col->ngeoms; i++ ) \n\t{\n\tif( col->geoms[i] )\n\t\tchar geomtype = TYPE_GETTYPE(col->geoms[i]->type);\n\t\tif ( geomtype == reqtype )  {\n\t\t\textracted_geoms[extracted_curgeom] = col->geoms[i];\n\t\t\textracted_curgeom++;\n\t\t\tcontinue;\n\t\t}\n\t\telse {\n\t\t\tif ( geomtype == COLLECTIONTYPE ) {\n\t\t\t\tLWGEOM *colgeom;\n\t\t\t\tcolgeom = lwcollection_extract(col->geoms[i], type);\n\t\t\t\textracted_geoms[extracted_curgeom] = colgeom->geoms;\n\t\t\t\textracted_curgeom++;\n\t\t\t\tif( colgeom->bbox ) lwfree(colgeom->bbox);\n\t\t\t\tlwfree(colgeom);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\nTODO: pramsey\n}\n*/\n\n\n\nvoid lwcollection_free(LWCOLLECTION *col) \n{\n\tint i;\n\tif( col->bbox ) \n\t{\n\t\tlwfree(col->bbox);\n\t}\n\tfor ( i = 0; i < col->ngeoms; i++ ) \n\t{\n\t\tif( col->geoms[i] ) {\n\t\t\tswitch( TYPE_GETTYPE(col->geoms[i]->type) )\n\t\t\t{\n\t\t\t\tcase POINTTYPE:\n\t\t\t\t\tlwpoint_free((LWPOINT*)col->geoms[i]);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LINETYPE:\n\t\t\t\t\tlwline_free((LWLINE*)col->geoms[i]);\n\t\t\t\t\tbreak;\n\t\t\t\tcase POLYGONTYPE:\n\t\t\t\t\tlwpoly_free((LWPOLY*)col->geoms[i]);\n\t\t\t\t\tbreak;\n\t\t\t\tcase MULTIPOINTTYPE:\n\t\t\t\t\tlwmpoint_free((LWMPOINT*)col->geoms[i]);\n\t\t\t\t\tbreak;\n\t\t\t\tcase MULTILINETYPE:\n\t\t\t\t\tlwmline_free((LWMLINE*)col->geoms[i]);\n\t\t\t\t\tbreak;\n\t\t\t\tcase MULTIPOLYGONTYPE:\n\t\t\t\t\tlwmpoly_free((LWMPOLY*)col->geoms[i]);\n\t\t\t\t\tbreak;\n\t\t\t\tcase COLLECTIONTYPE:\n\t\t\t\t\tlwcollection_free((LWCOLLECTION*)col->geoms[i]);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tif( col->geoms ) \n\t{\n\t\tlwfree(col->geoms);\n\t}\n\tlwfree(col);\n\t\n};\n\nBOX3D *lwcollection_compute_box3d(LWCOLLECTION *col)\n{\n\tint i;\n    BOX3D *boxfinal = NULL;\n    BOX3D *boxtmp1 = NULL;\n    BOX3D *boxtmp2 = NULL;\n\tfor ( i = 0; i < col->ngeoms; i++ ) \n\t{\n\t\tif( col->geoms[i] ) {\n\t\t\tswitch( TYPE_GETTYPE(col->geoms[i]->type) )\n\t\t\t{\n\t\t\t\tcase POINTTYPE:\n                    boxtmp1 = lwpoint_compute_box3d((LWPOINT*)(col->geoms[i]));\n                    break;\n\t\t\t\tcase LINETYPE:\n                    boxtmp1 = lwline_compute_box3d((LWLINE*)(col->geoms[i]));\n\t\t\t\t\tbreak;\n\t\t\t\tcase POLYGONTYPE:\n                    boxtmp1 = lwpoly_compute_box3d((LWPOLY*)(col->geoms[i]));\n\t\t\t\t\tbreak;\n\t\t\t\tcase CIRCSTRINGTYPE:\n\t\t\t\t\tboxtmp1 = lwcircstring_compute_box3d((LWCIRCSTRING *)(col->geoms[i]));\n\t\t\t\t\tbreak;\n\t\t\t\tcase COMPOUNDTYPE:\n\t\t\t\tcase CURVEPOLYTYPE:\n\t\t\t\tcase MULTIPOINTTYPE:\n\t\t\t\tcase MULTILINETYPE:\n\t\t\t\tcase MULTIPOLYGONTYPE:\n\t\t\t\tcase MULTICURVETYPE:\n\t\t\t\tcase MULTISURFACETYPE:\n\t\t\t\tcase COLLECTIONTYPE:\n                    boxtmp1 = lwcollection_compute_box3d((LWCOLLECTION*)(col->geoms[i]));\n                    boxfinal = box3d_union(boxtmp1, boxtmp2);\n\t\t\t\t\tbreak;\n\t\t\t}\n            boxtmp2 = boxfinal;\n            boxfinal = box3d_union(boxtmp1, boxtmp2);\n\t\t\tif( boxtmp1 && boxtmp1 != boxfinal ) \n\t\t\t{\n                lwfree(boxtmp1);\n                boxtmp1 = NULL;\n\t\t    }\n\t\t\tif( boxtmp2 && boxtmp2 != boxfinal ) \n\t\t\t{\n                lwfree(boxtmp2);\n                boxtmp2 = NULL;\n\t\t    }\n\t\t}\n\t}\n\treturn boxfinal;\n}\n"
  },
  {
    "path": "src/liblwgeom/lwcompound.c",
    "content": "/**********************************************************************\n * $Id: lwcompound.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"liblwgeom.h\"\n\nLWCOMPOUND *\nlwcompound_deserialize(uchar *serialized)\n{\n        LWCOMPOUND *result;\n        LWGEOM_INSPECTED *insp;\n        int type = lwgeom_getType(serialized[0]);\n        int i;\n\n        if(type != COMPOUNDTYPE)\n        {\n                lwerror(\"lwcompound_deserialize called on non compound: %d\", type);\n                return NULL;\n        }\n\n        insp = lwgeom_inspect(serialized);\n\n        result = lwalloc(sizeof(LWCOMPOUND));\n        result->type = insp->type;\n        result->SRID = insp->SRID;\n        result->ngeoms = insp->ngeometries;\n        result->geoms = lwalloc(sizeof(LWGEOM *)*insp->ngeometries);\n\n        if(lwgeom_hasBBOX(serialized[0]))\n        {\n                result->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n                memcpy(result->bbox, serialized + 1, sizeof(BOX2DFLOAT4));\n        }\n        else result->bbox = NULL;\n\n        for(i = 0; i < insp->ngeometries; i++)\n        {\n                if(lwgeom_getType(insp->sub_geoms[i][0]) == LINETYPE)\n                        result->geoms[i] = (LWGEOM *)lwline_deserialize(insp->sub_geoms[i]);\n                else\n                        result->geoms[i] = (LWGEOM *)lwcircstring_deserialize(insp->sub_geoms[i]);\n                if(TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type))\n                {\n                        lwerror(\"Mixed dimensions (compound: %d, line/circularstring %d:%d)\",\n                            TYPE_NDIMS(result->type), i,\n                            TYPE_NDIMS(result->geoms[i]->type)\n                        );\n                        lwfree(result);\n                        return NULL;\n                }\n        }\n        return result;\n}\n\n/*\n * Add 'what' to this string at position 'where'\n * where=0 == prepend\n * where=-1 == append\n * Returns a COMPOUND or a GEOMETRYCOLLECTION\n */\nLWGEOM *\nlwcompound_add(const LWCOMPOUND *to, uint32 where, const LWGEOM *what)\n{\n        LWCOLLECTION *col;\n        LWGEOM **geoms;\n        int newtype;\n\n        LWDEBUG(2, \"lwcompound_add called.\");\n\n        if(where != -1 && where != 0)\n        {\n                lwerror(\"lwcompound_add only supports 0 or -1 as a second argument, not %d\", where);\n                return NULL;\n        }\n\n        /* dimensions compatibility are checked by caller */\n\n        /* Construct geoms array */\n        geoms = lwalloc(sizeof(LWGEOM *)*2);\n        if(where == -1) /* append */\n        {\n                geoms[0] = lwgeom_clone((LWGEOM *)to);\n                geoms[1] = lwgeom_clone(what);\n        }\n        else /* prepend */\n        {\n                geoms[0] = lwgeom_clone(what);\n                geoms[1] = lwgeom_clone((LWGEOM *)to);\n        }\n\n        /* reset SRID and wantbbox flag from component types */\n        geoms[0]->SRID = geoms[1]->SRID = -1;\n        TYPE_SETHASSRID(geoms[0]->type, 0);\n        TYPE_SETHASSRID(geoms[1]->type, 0);\n        TYPE_SETHASBBOX(geoms[0]->type, 0);\n        TYPE_SETHASBBOX(geoms[1]->type, 0);\n\n        /* Find appropriate geom type */\n        if(TYPE_GETTYPE(what->type) == LINETYPE || TYPE_GETTYPE(what->type) == CIRCSTRINGTYPE) newtype = COMPOUNDTYPE;\n        else newtype = COLLECTIONTYPE;\n\n        col = lwcollection_construct(newtype,\n                to->SRID, NULL, 2, geoms);\n\n        return (LWGEOM *)col;\n}\n\n"
  },
  {
    "path": "src/liblwgeom/lwcurvepoly.c",
    "content": "/**********************************************************************\n * $Id: lwcurvepoly.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n/* basic LWCURVEPOLY manipulation */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"liblwgeom.h\"\n\n\nLWCURVEPOLY *\nlwcurvepoly_deserialize(uchar *srl)\n{\n        LWCURVEPOLY *result;\n        LWGEOM_INSPECTED *insp;\n        int type = lwgeom_getType(srl[0]);\n        int i;\n\n        LWDEBUG(3, \"lwcurvepoly_deserialize called.\");\n\n        if(type != CURVEPOLYTYPE)\n        {\n                lwerror(\"lwcurvepoly_deserialize called on NON curvepoly: %d\",\n                        type);\n                return NULL;\n        }\n\n        insp = lwgeom_inspect(srl);\n\n        result = lwalloc(sizeof(LWCURVEPOLY));\n        result->type = insp->type;\n        result->SRID = insp->SRID;\n        result->nrings = insp->ngeometries;\n        result->rings = lwalloc(sizeof(LWGEOM *)*insp->ngeometries);\n\n        if(lwgeom_hasBBOX(srl[0]))\n        {\n                result->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n                memcpy(result->bbox, srl + 1, sizeof(BOX2DFLOAT4));\n        }\n        else result->bbox = NULL;\n\n        for(i = 0; i < insp->ngeometries; i++)\n        {\n                result->rings[i] = lwgeom_deserialize(insp->sub_geoms[i]);\n                if(lwgeom_getType(result->rings[i]->type) != CIRCSTRINGTYPE \n                        && lwgeom_getType(result->rings[i]->type) != LINETYPE)\n                {\n                        lwerror(\"Only Circularstrings and Linestrings are currently supported as rings, not %s (%d)\", lwgeom_typename(result->rings[i]->type), result->rings[i]->type);\n                        lwfree(result);\n                        lwfree(insp);\n                        return NULL;\n                }\n                if(TYPE_NDIMS(result->rings[i]->type) != TYPE_NDIMS(result->type))\n                {\n                        lwerror(\"Mixed dimensions (curvepoly %d, ring %d)\",\n                                TYPE_NDIMS(result->type), i, \n                                TYPE_NDIMS(result->rings[i]->type));\n                        lwfree(result);\n                        lwfree(insp);\n                        return NULL;\n                }\n        }\n        return result;\n}\n\nLWGEOM *\nlwcurvepoly_add(const LWCURVEPOLY *to, uint32 where, const LWGEOM *what)\n{\n        /* TODO */\n        lwerror(\"lwcurvepoly_add not yet implemented.\");\n        return NULL;\n}\n\n\n\n"
  },
  {
    "path": "src/liblwgeom/lwgeom.c",
    "content": "/**********************************************************************\n * $Id: lwgeom.c 3812 2009-03-09 14:36:15Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n\n#include \"liblwgeom.h\"\n#include \"wktparse.h\"\n\n\nLWGEOM *\nlwgeom_deserialize(uchar *srl)\n{\n\tint type = lwgeom_getType(srl[0]);\n\n\tLWDEBUGF(2, \"lwgeom_deserialize got %d - %s\", type, lwgeom_typename(type));\n\n\tswitch (type)\n\t{\n\t\tcase POINTTYPE:\n\t\t\treturn (LWGEOM *)lwpoint_deserialize(srl);\n\t\tcase LINETYPE:\n\t\t\treturn (LWGEOM *)lwline_deserialize(srl);\n                case CIRCSTRINGTYPE:\n                        return (LWGEOM *)lwcircstring_deserialize(srl);\n\t\tcase POLYGONTYPE:\n\t\t\treturn (LWGEOM *)lwpoly_deserialize(srl);\n\t\tcase MULTIPOINTTYPE:\n\t\t\treturn (LWGEOM *)lwmpoint_deserialize(srl);\n\t\tcase MULTILINETYPE:\n\t\t\treturn (LWGEOM *)lwmline_deserialize(srl);\n\t\tcase MULTIPOLYGONTYPE:\n\t\t\treturn (LWGEOM *)lwmpoly_deserialize(srl);\n\t\tcase COLLECTIONTYPE:\n\t\t\treturn (LWGEOM *)lwcollection_deserialize(srl);\n                case COMPOUNDTYPE:\n                        return (LWGEOM *)lwcompound_deserialize(srl);\n                case CURVEPOLYTYPE:\n                        return (LWGEOM *)lwcurvepoly_deserialize(srl);\n                case MULTICURVETYPE:\n                        return (LWGEOM *)lwmcurve_deserialize(srl);\n                case MULTISURFACETYPE:\n                        return (LWGEOM *)lwmsurface_deserialize(srl);\n\t\tdefault:\n\t\t\tlwerror(\"Unknown geometry type: %d\", type);\n\n\t\t\treturn NULL;\n\t}\n\n}\n\nsize_t\nlwgeom_serialize_size(LWGEOM *lwgeom)\n{\n\tint type = TYPE_GETTYPE(lwgeom->type);\n\n\tLWDEBUGF(2, \"lwgeom_serialize_size(%s) called\", lwgeom_typename(type));\n\n\tswitch (type)\n\t{\n\t\tcase POINTTYPE:\n\t\t\treturn lwpoint_serialize_size((LWPOINT *)lwgeom);\n\t\tcase LINETYPE:\n\t\t\treturn lwline_serialize_size((LWLINE *)lwgeom);\n\t\tcase POLYGONTYPE:\n\t\t\treturn lwpoly_serialize_size((LWPOLY *)lwgeom);\n                case CIRCSTRINGTYPE:\n                        return lwcircstring_serialize_size((LWCIRCSTRING *)lwgeom);\n                case CURVEPOLYTYPE:\n                case COMPOUNDTYPE:\n\t\tcase MULTIPOINTTYPE:\n\t\tcase MULTILINETYPE:\n                case MULTICURVETYPE:\n\t\tcase MULTIPOLYGONTYPE:\n                case MULTISURFACETYPE:\n\t\tcase COLLECTIONTYPE:\n\t\t\treturn lwcollection_serialize_size((LWCOLLECTION *)lwgeom);\n\t\tdefault:\n\t\t\tlwerror(\"Unknown geometry type: %d\", type);\n\n\t\t\treturn 0;\n\t}\n}\n\nvoid\nlwgeom_serialize_buf(LWGEOM *lwgeom, uchar *buf, size_t *retsize)\n{\n\tint type = TYPE_GETTYPE(lwgeom->type);\n\n\tLWDEBUGF(2, \"lwgeom_serialize_buf called with a %s\",\n\t\t\tlwgeom_typename(type));\n\n\tswitch (type)\n\t{\n\t\tcase POINTTYPE:\n\t\t\tlwpoint_serialize_buf((LWPOINT *)lwgeom, buf, retsize);\n\t\t\tbreak;\n\t\tcase LINETYPE:\n\t\t\tlwline_serialize_buf((LWLINE *)lwgeom, buf, retsize);\n\t\t\tbreak;\n\t\tcase POLYGONTYPE:\n\t\t\tlwpoly_serialize_buf((LWPOLY *)lwgeom, buf, retsize);\n\t\t\tbreak;\n                case CIRCSTRINGTYPE:\n                        lwcircstring_serialize_buf((LWCIRCSTRING *)lwgeom, buf, retsize);\n                        break;\n                case CURVEPOLYTYPE:\n                case COMPOUNDTYPE:\n\t\tcase MULTIPOINTTYPE:\n\t\tcase MULTILINETYPE:\n                case MULTICURVETYPE:\n\t\tcase MULTIPOLYGONTYPE:\n                case MULTISURFACETYPE:\n\t\tcase COLLECTIONTYPE:\n\t\t\tlwcollection_serialize_buf((LWCOLLECTION *)lwgeom, buf,\n\t\t\t\tretsize);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tlwerror(\"Unknown geometry type: %d\", type);\n\t\t\treturn;\n\t}\n\treturn;\n}\n\nuchar *\nlwgeom_serialize(LWGEOM *lwgeom)\n{\n\tsize_t size = lwgeom_serialize_size(lwgeom);\n\tsize_t retsize;\n\tuchar *serialized = lwalloc(size);\n\n\tlwgeom_serialize_buf(lwgeom, serialized, &retsize);\n\n#if POSTGIS_DEBUG_LEVEL > 0\n\tif ( retsize != size )\n\t{\n\t\tlwerror(\"lwgeom_serialize: computed size %d, returned size %d\",\n\t\t\tsize, retsize);\n\t}\n#endif\n\n\treturn serialized;\n}\n\n/* Force Right-hand-rule on LWGEOM polygons */\nvoid\nlwgeom_forceRHR(LWGEOM *lwgeom)\n{\n\tLWCOLLECTION *coll;\n\tint i;\n\n\tswitch (TYPE_GETTYPE(lwgeom->type))\n\t{\n\t\tcase POLYGONTYPE:\n\t\t\tlwpoly_forceRHR((LWPOLY *)lwgeom);\n\t\t\treturn;\n\n\t\tcase MULTIPOLYGONTYPE:\n\t\tcase COLLECTIONTYPE:\n\t\t\tcoll = (LWCOLLECTION *)lwgeom;\n\t\t\tfor (i=0; i<coll->ngeoms; i++)\n\t\t\t\tlwgeom_forceRHR(coll->geoms[i]);\n\t\t\treturn;\n\t}\n}\n\n/* Reverse vertex order of LWGEOM */\nvoid\nlwgeom_reverse(LWGEOM *lwgeom)\n{\n\tint i;\n\tLWCOLLECTION *col;\n\n\tswitch (TYPE_GETTYPE(lwgeom->type))\n\t{\n\t\tcase LINETYPE:\n\t\t\tlwline_reverse((LWLINE *)lwgeom);\n\t\t\treturn;\n\t\tcase POLYGONTYPE:\n\t\t\tlwpoly_reverse((LWPOLY *)lwgeom);\n\t\t\treturn;\n\t\tcase MULTILINETYPE:\n\t\tcase MULTIPOLYGONTYPE:\n\t\tcase COLLECTIONTYPE:\n\t\t\tcol = (LWCOLLECTION *)lwgeom;\n\t\t\tfor (i=0; i<col->ngeoms; i++)\n\t\t\t\tlwgeom_reverse(col->geoms[i]);\n\t\t\treturn;\n\t}\n}\n\nBOX3D *lwgeom_compute_box3d(const LWGEOM *lwgeom)\n{\n    if( ! lwgeom ) return NULL;\n    \n    switch(TYPE_GETTYPE(lwgeom->type))\n\t{\n\t\tcase POINTTYPE:\n\t\t\treturn lwpoint_compute_box3d((LWPOINT *)lwgeom);\n\t\tcase LINETYPE:\n\t\t\treturn lwline_compute_box3d((LWLINE *)lwgeom);\n        case CIRCSTRINGTYPE:\n            return lwcircstring_compute_box3d((LWCIRCSTRING *)lwgeom);\n\t\tcase POLYGONTYPE:\n\t\t\treturn lwpoly_compute_box3d((LWPOLY *)lwgeom);\n        case COMPOUNDTYPE:\n        case CURVEPOLYTYPE:\n\t\tcase MULTIPOINTTYPE:\n\t\tcase MULTILINETYPE:\n        case MULTICURVETYPE:\n\t\tcase MULTIPOLYGONTYPE:\n        case MULTISURFACETYPE:\n\t\tcase COLLECTIONTYPE:\n\t\t\treturn lwcollection_compute_box3d((LWCOLLECTION *)lwgeom);\n\t}\n\t/* Never get here, please. */\n\treturn NULL;\n}\n\nint\nlwgeom_compute_box2d_p(LWGEOM *lwgeom, BOX2DFLOAT4 *buf)\n{\n        LWDEBUGF(2, \"lwgeom_compute_box2d_p called of %p of type %d.\", lwgeom, TYPE_GETTYPE(lwgeom->type));\n\n\tswitch(TYPE_GETTYPE(lwgeom->type))\n\t{\n\t\tcase POINTTYPE:\n\t\t\treturn lwpoint_compute_box2d_p((LWPOINT *)lwgeom, buf);\n\t\tcase LINETYPE:\n\t\t\treturn lwline_compute_box2d_p((LWLINE *)lwgeom, buf);\n                case CIRCSTRINGTYPE:\n                        return lwcircstring_compute_box2d_p((LWCIRCSTRING *)lwgeom, buf);\n\t\tcase POLYGONTYPE:\n\t\t\treturn lwpoly_compute_box2d_p((LWPOLY *)lwgeom, buf);\n                case COMPOUNDTYPE:\n                case CURVEPOLYTYPE:\n\t\tcase MULTIPOINTTYPE:\n\t\tcase MULTILINETYPE:\n                case MULTICURVETYPE:\n\t\tcase MULTIPOLYGONTYPE:\n                case MULTISURFACETYPE:\n\t\tcase COLLECTIONTYPE:\n\t\t\treturn lwcollection_compute_box2d_p((LWCOLLECTION *)lwgeom, buf);\n\t}\n\treturn 0;\n}\n\n/*\n * dont forget to lwfree() result\n */\nBOX2DFLOAT4 *\nlwgeom_compute_box2d(LWGEOM *lwgeom)\n{\n\tBOX2DFLOAT4 *result = lwalloc(sizeof(BOX2DFLOAT4));\n\tif ( lwgeom_compute_box2d_p(lwgeom, result) ) return result;\n\telse  {\n\t\tlwfree(result);\n\t\treturn NULL;\n\t}\n}\n\nLWPOINT *\nlwgeom_as_lwpoint(LWGEOM *lwgeom)\n{\n\tif ( TYPE_GETTYPE(lwgeom->type) == POINTTYPE )\n\t\treturn (LWPOINT *)lwgeom;\n\telse return NULL;\n}\n\nLWLINE *\nlwgeom_as_lwline(LWGEOM *lwgeom)\n{\n\tif ( TYPE_GETTYPE(lwgeom->type) == LINETYPE )\n\t\treturn (LWLINE *)lwgeom;\n\telse return NULL;\n}\n\nLWCIRCSTRING *\nlwgeom_as_lwcircstring(LWGEOM *lwgeom)\n{\n        if( TYPE_GETTYPE(lwgeom->type) == CIRCSTRINGTYPE )\n                return (LWCIRCSTRING *)lwgeom;\n        else return NULL;\n}\n\nLWPOLY *\nlwgeom_as_lwpoly(LWGEOM *lwgeom)\n{\n\tif ( TYPE_GETTYPE(lwgeom->type) == POLYGONTYPE )\n\t\treturn (LWPOLY *)lwgeom;\n\telse return NULL;\n}\n\nLWCOLLECTION *\nlwgeom_as_lwcollection(LWGEOM *lwgeom)\n{\n\tif ( TYPE_GETTYPE(lwgeom->type) >= MULTIPOINTTYPE \n            && TYPE_GETTYPE(lwgeom->type) <= COLLECTIONTYPE)\n\t\treturn (LWCOLLECTION *)lwgeom;\n\telse return NULL;\n}\n\nLWMPOINT *\nlwgeom_as_lwmpoint(LWGEOM *lwgeom)\n{\n\tif ( TYPE_GETTYPE(lwgeom->type) == MULTIPOINTTYPE )\n\t\treturn (LWMPOINT *)lwgeom;\n\telse return NULL;\n}\n\nLWMLINE *\nlwgeom_as_lwmline(LWGEOM *lwgeom)\n{\n\tif ( TYPE_GETTYPE(lwgeom->type) == MULTILINETYPE )\n\t\treturn (LWMLINE *)lwgeom;\n\telse return NULL;\n}\n\nLWMPOLY *\nlwgeom_as_lwmpoly(LWGEOM *lwgeom)\n{\n\tif ( TYPE_GETTYPE(lwgeom->type) == MULTIPOLYGONTYPE )\n\t\treturn (LWMPOLY *)lwgeom;\n\telse return NULL;\n}\n\nLWGEOM *lwmpoly_as_lwgeom(LWMPOLY *obj) { return (LWGEOM *)obj; }\nLWGEOM *lwmline_as_lwgeom(LWMLINE *obj) { return (LWGEOM *)obj; }\nLWGEOM *lwmpoint_as_lwgeom(LWMPOINT *obj) { return (LWGEOM *)obj; }\nLWGEOM *lwcollection_as_lwgeom(LWCOLLECTION *obj) { return (LWGEOM *)obj; }\nLWGEOM *lwpoly_as_lwgeom(LWPOLY *obj) { return (LWGEOM *)obj; }\nLWGEOM *lwline_as_lwgeom(LWLINE *obj) { return (LWGEOM *)obj; }\nLWGEOM *lwpoint_as_lwgeom(LWPOINT *obj) { return (LWGEOM *)obj; }\n\nvoid\nlwgeom_release(LWGEOM *lwgeom)\n{\n\tuint32 i;\n\tLWCOLLECTION *col;\n\n#ifdef INTEGRITY_CHECKS\n\tif ( ! lwgeom )\n\t\tlwerror(\"lwgeom_release: someone called on 0x0\");\n#endif\n\n\t/* Drop bounding box (always a copy) */\n\tif ( lwgeom->bbox ) {\n                LWDEBUG(3, \"lwgeom_release: releasing bbox.\");\n\n                lwfree(lwgeom->bbox);\n        }\n\n\t/* Collection */\n\tif ( (col=lwgeom_as_lwcollection(lwgeom)) )\n\t{\n                LWDEBUG(3, \"lwgeom_release: Releasing collection.\");\n\n\t\tfor (i=0; i<col->ngeoms; i++)\n\t\t{\n\t\t\tlwgeom_release(col->geoms[i]);\n\t\t}\n\t\tlwfree(lwgeom);\n\t}\n\n\t/* Single element */\n\telse lwfree(lwgeom);\n\n}\n\n\n/* Clone an LWGEOM object. POINTARRAY are not copied. */\nLWGEOM *\nlwgeom_clone(const LWGEOM *lwgeom)\n{\n        LWDEBUGF(2, \"lwgeom_clone called with %p, %d\", lwgeom, TYPE_GETTYPE(lwgeom->type));\n\n\tswitch(TYPE_GETTYPE(lwgeom->type))\n\t{\n\t\tcase POINTTYPE:\n\t\t\treturn (LWGEOM *)lwpoint_clone((LWPOINT *)lwgeom);\n\t\tcase LINETYPE:\n\t\t\treturn (LWGEOM *)lwline_clone((LWLINE *)lwgeom);\n                case CIRCSTRINGTYPE:\n                        return (LWGEOM *)lwcircstring_clone((LWCIRCSTRING *)lwgeom);\n\t\tcase POLYGONTYPE:\n\t\t\treturn (LWGEOM *)lwpoly_clone((LWPOLY *)lwgeom);\n                case COMPOUNDTYPE:\n                case CURVEPOLYTYPE:\n\t\tcase MULTIPOINTTYPE:\n\t\tcase MULTILINETYPE:\n                case MULTICURVETYPE:\n\t\tcase MULTIPOLYGONTYPE:\n                case MULTISURFACETYPE:\n\t\tcase COLLECTIONTYPE:\n\t\t\treturn (LWGEOM *)lwcollection_clone((LWCOLLECTION *)lwgeom);\n\t\tdefault:\n\t\t\treturn NULL;\n\t}\n}\n\n/*\n * Add 'what' to 'to' at position 'where'\n *\n * where=0 == prepend\n * where=-1 == append\n * Appended-to LWGEOM gets a new type based on new condition.\n * Mix of dimensions is not allowed (TODO: allow it?).\n */\nLWGEOM *\nlwgeom_add(const LWGEOM *to, uint32 where, const LWGEOM *what)\n{\n\tif ( TYPE_NDIMS(what->type) != TYPE_NDIMS(to->type) )\n\t{\n\t\tlwerror(\"lwgeom_add: mixed dimensions not supported\");\n\t\treturn NULL;\n\t}\n\n\tLWDEBUGF(2, \"lwgeom_add(%s, %d, %s) called\",\n\t\tlwgeom_typename(TYPE_GETTYPE(to->type)),\n\t\twhere,\n\t\tlwgeom_typename(TYPE_GETTYPE(what->type)));\n\n\tswitch(TYPE_GETTYPE(to->type))\n\t{\n\t\tcase POINTTYPE:\n\t\t\treturn (LWGEOM *)lwpoint_add((const LWPOINT *)to, where, what);\n\t\tcase LINETYPE:\n\t\t\treturn (LWGEOM *)lwline_add((const LWLINE *)to, where, what);\n\n                case CIRCSTRINGTYPE:\n                        return (LWGEOM *)lwcircstring_add((const LWCIRCSTRING *)to, where, what);\n\n\t\tcase POLYGONTYPE:\n\t\t\treturn (LWGEOM *)lwpoly_add((const LWPOLY *)to, where, what);\n\n                case COMPOUNDTYPE:\n                        return (LWGEOM *)lwcompound_add((const LWCOMPOUND *)to, where, what);\n\n                case CURVEPOLYTYPE:\n                        return (LWGEOM *)lwcurvepoly_add((const LWCURVEPOLY *)to, where, what);\n\n\t\tcase MULTIPOINTTYPE:\n\t\t\treturn (LWGEOM *)lwmpoint_add((const LWMPOINT *)to,\n\t\t\t\twhere, what);\n\n\t\tcase MULTILINETYPE:\n\t\t\treturn (LWGEOM *)lwmline_add((const LWMLINE *)to,\n\t\t\t\twhere, what);\n\n                case MULTICURVETYPE:\n                        return (LWGEOM *)lwmcurve_add((const LWMCURVE *)to,\n                                where, what);\n\n\t\tcase MULTIPOLYGONTYPE:\n\t\t\treturn (LWGEOM *)lwmpoly_add((const LWMPOLY *)to,\n\t\t\t\twhere, what);\n\n                case MULTISURFACETYPE:\n                        return (LWGEOM *)lwmsurface_add((const LWMSURFACE *)to,\n                                where, what);\n\n\t\tcase COLLECTIONTYPE:\n\t\t\treturn (LWGEOM *)lwcollection_add(\n\t\t\t\t(const LWCOLLECTION *)to, where, what);\n\n\t\tdefault:\n\t\t\tlwerror(\"lwgeom_add: unknown geometry type: %d\",\n\t\t\t\tTYPE_GETTYPE(to->type));\n\t\t\treturn NULL;\n\t}\n}\n\n\n/*\n * Return an alloced string\n */\nchar *\nlwgeom_to_ewkt(LWGEOM *lwgeom, int flags)\n{\n\tLWGEOM_UNPARSER_RESULT lwg_unparser_result;\n\tuchar *serialized = lwgeom_serialize(lwgeom);\n\tint result;\n\n\tif ( ! serialized ) {\n\t\tlwerror(\"Error serializing geom %p\", lwgeom);\n\t}\n\n\tresult = unparse_WKT(&lwg_unparser_result, serialized, lwalloc, lwfree, flags);\n\tlwfree(serialized);\n\n\treturn lwg_unparser_result.wkoutput;\n}\n\n/*\n * Return an alloced string\n */\nchar *\nlwgeom_to_hexwkb(LWGEOM *lwgeom, int flags, unsigned int byteorder)\n{\n\tLWGEOM_UNPARSER_RESULT lwg_unparser_result;\n\tuchar *serialized = lwgeom_serialize(lwgeom);\n\tint result;\n\n\tresult = unparse_WKB(&lwg_unparser_result, serialized, lwalloc, lwfree, flags, byteorder,1);\n\n\tlwfree(serialized);\n\treturn lwg_unparser_result.wkoutput;\n}\n\n/*\n * Return an alloced string\n */\nuchar *\nlwgeom_to_ewkb(LWGEOM *lwgeom, int flags, char byteorder, size_t *outsize)\n{\n\tLWGEOM_UNPARSER_RESULT lwg_unparser_result;\n\tuchar *serialized = lwgeom_serialize(lwgeom);\n\tint result;\n\n\t/*\n\t * We cast return to \"unsigned\" char as we are\n\t * requesting a \"binary\" output, not HEX\n\t * (last argument set to 0)\n\t */\n\tresult = unparse_WKB(&lwg_unparser_result, serialized, lwalloc, lwfree,\n\t\tflags, byteorder, 0);\n\tlwfree(serialized);\n\treturn (uchar *)lwg_unparser_result.wkoutput;\n}\n\n/*\n * Make an LWGEOM object from a EWKB binary representation.\n * Currently highly unoptimized as it:\n * \t- convert EWKB to HEXEWKB \n *\t- construct PG_LWGEOM\n *\t- deserialize it\n */\nLWGEOM *\nlwgeom_from_ewkb(uchar *ewkb, int flags, size_t size)\n{\n\tsize_t hexewkblen = size*2;\n\tchar *hexewkb;\n\tlong int i;\n\tint result;\n\tLWGEOM *ret;\n\tLWGEOM_PARSER_RESULT lwg_parser_result;\n\n\t/* \"HEXify\" the EWKB */\n\thexewkb = lwalloc(hexewkblen+1);\n\tfor (i=0; i<size; ++i) deparse_hex(ewkb[i], &hexewkb[i*2]);\n\thexewkb[hexewkblen] = '\\0';\n\n\t/* Rely on grammar parser to construct a LWGEOM */\n\tresult = serialized_lwgeom_from_ewkt(&lwg_parser_result, hexewkb, flags);\n\tif (result)\n\t\tlwerror(\"%s\", (char *)lwg_parser_result.message);\n\n\t/* Free intermediate HEXified representation */\n\tlwfree(hexewkb);\n\n\t/* Deserialize */\n\tret = lwgeom_deserialize(lwg_parser_result.serialized_lwgeom);\n\n\treturn ret;\n}\n\n/*\n * Make an LWGEOM object from a EWKT representation.\n */\nLWGEOM *\nlwgeom_from_ewkt(char *ewkt, int flags)\n{\n\tint result;\n\tLWGEOM *ret;\n\tLWGEOM_PARSER_RESULT lwg_parser_result;\n\n\t/* Rely on grammar parser to construct a LWGEOM */\n\tresult = serialized_lwgeom_from_ewkt(&lwg_parser_result, ewkt, flags);\n\tif (result)\n\t\tlwerror(\"%s\", (char *)lwg_parser_result.message);\n\n\t/* Deserialize */\n\tret = lwgeom_deserialize(lwg_parser_result.serialized_lwgeom);\n\n\treturn ret;\n}\n\n/*\n * Parser functions for working with serialized LWGEOMs. Useful for cases where\n * the function input is already serialized, e.g. some input and output functions\n */\n\n/*\n * Make a serialzed LWGEOM object from a WKT input string\n */\nint\nserialized_lwgeom_from_ewkt(LWGEOM_PARSER_RESULT *lwg_parser_result, char *wkt_input, int flags)\n{\n\n\tint result = parse_lwg(lwg_parser_result, wkt_input, flags,\n\t\tlwalloc, lwerror);\n\n\tLWDEBUGF(2, \"serialized_lwgeom_from_ewkt with %s\",wkt_input);\n\n\treturn result;\n}\n\n/*\n * Return an alloced string\n */\nint\nserialized_lwgeom_to_ewkt(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar *serialized, int flags)\n{\n\tint result;\n\n\tresult = unparse_WKT(lwg_unparser_result, serialized, lwalloc, lwfree, flags);\n\n\treturn result;\n}\n\n/*\n * Return an alloced string\n */\nint\nserialized_lwgeom_from_hexwkb(LWGEOM_PARSER_RESULT *lwg_parser_result, char *hexwkb_input, int flags)\n{\n\t/* NOTE: it is actually the same combined WKT/WKB parser that decodes HEXEWKB into LWGEOMs! */\n\tint result = parse_lwg(lwg_parser_result, hexwkb_input, flags,\n\t\tlwalloc, lwerror);\n\n\tLWDEBUGF(2, \"serialized_lwgeom_from_hexwkb with %s\", hexwkb_input);\n\n\treturn result;\n}\n\n/*\n * Return an alloced string\n */\nint\nserialized_lwgeom_to_hexwkb(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar *serialized, int flags, unsigned int byteorder)\n{\n\tint result;\n\n\tresult = unparse_WKB(lwg_unparser_result, serialized, lwalloc, lwfree, flags, byteorder, 1);\n\n\treturn result;\n}\n\n/*\n * Return an alloced string\n */\nint\nserialized_lwgeom_to_ewkb(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar *serialized, int flags, unsigned int byteorder)\n{\n\tint result;\n\n\tresult = unparse_WKB(lwg_unparser_result, serialized, lwalloc, lwfree, flags, byteorder, 0);\n\n\treturn result;\n}\n\n/*\n * geom1 same as geom2\n *  iff\n *      + have same type \n *\t+ have same # objects\n *      + have same bvol\n *      + each object in geom1 has a corresponding object in geom2 (see above)\n */\nchar\nlwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)\n{\n\tLWDEBUGF(2, \"lwgeom_same(%s, %s) called\",\n\t\tlwgeom_typename(TYPE_GETTYPE(lwgeom1->type)),\n\t\tlwgeom_typename(TYPE_GETTYPE(lwgeom2->type)));\n\n\tif ( TYPE_GETTYPE(lwgeom1->type) != TYPE_GETTYPE(lwgeom2->type) )\n\t{\n\t\tLWDEBUG(3, \" type differ\");\n\n\t\treturn 0;\n\t}\n\n\tif ( TYPE_GETZM(lwgeom1->type) != TYPE_GETZM(lwgeom2->type) )\n\t{\n\t\tLWDEBUG(3, \" ZM flags differ\");\n\n\t\treturn 0;\n\t}\n\n\t/* Check boxes if both already computed  */\n\tif ( lwgeom1->bbox && lwgeom2->bbox )\n\t{\n\t\t/*lwnotice(\"bbox1:%p, bbox2:%p\", lwgeom1->bbox, lwgeom2->bbox);*/\n\t\tif ( ! box2d_same(lwgeom1->bbox, lwgeom2->bbox) )\n\t\t{\n\t\t\tLWDEBUG(3, \" bounding boxes differ\");\n\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/* geoms have same type, invoke type-specific function */\n\tswitch(TYPE_GETTYPE(lwgeom1->type))\n\t{\n\t\tcase POINTTYPE:\n\t\t\treturn lwpoint_same((LWPOINT *)lwgeom1,\n\t\t\t\t(LWPOINT *)lwgeom2);\n\t\tcase LINETYPE:\n\t\t\treturn lwline_same((LWLINE *)lwgeom1,\n\t\t\t\t(LWLINE *)lwgeom2);\n\t\tcase POLYGONTYPE:\n\t\t\treturn lwpoly_same((LWPOLY *)lwgeom1,\n\t\t\t\t(LWPOLY *)lwgeom2);\n\t\tcase MULTIPOINTTYPE:\n\t\tcase MULTILINETYPE:\n\t\tcase MULTIPOLYGONTYPE:\n\t\tcase COLLECTIONTYPE:\n\t\t\treturn lwcollection_same((LWCOLLECTION *)lwgeom1,\n\t\t\t\t(LWCOLLECTION *)lwgeom2);\n\t\tdefault:\n\t\t\tlwerror(\"lwgeom_same: unsupported geometry type: %s\",\n\t\t\t\tlwgeom_typename(TYPE_GETTYPE(lwgeom1->type)));\n\t\t\treturn 0;\n\t}\n\n}\n\nvoid\nlwgeom_changed(LWGEOM *lwgeom)\n{\n\tif ( lwgeom->bbox ) lwfree(lwgeom->bbox);\n\tlwgeom->bbox = NULL;\n\tTYPE_SETHASBBOX(lwgeom->type, 0);\n}\n\nvoid\nlwgeom_drop_bbox(LWGEOM *lwgeom)\n{\n\tif ( lwgeom->bbox ) lwfree(lwgeom->bbox);\n\tlwgeom->bbox = NULL;\n\tTYPE_SETHASBBOX(lwgeom->type, 0);\n}\n\n/*\n * Ensure there's a box in the LWGEOM.\n * If the box is already there just return,\n * else compute it.\n */\nvoid\nlwgeom_add_bbox(LWGEOM *lwgeom)\n{\n\tif ( lwgeom->bbox ) return;\n\tlwgeom->bbox = lwgeom_compute_box2d(lwgeom);\n\tTYPE_SETHASBBOX(lwgeom->type, 1);\n}\n\nvoid\nlwgeom_dropSRID(LWGEOM *lwgeom)\n{\n\tTYPE_SETHASSRID(lwgeom->type, 0);\n\tlwgeom->SRID = -1;\n}\n\nLWGEOM *\nlwgeom_segmentize2d(LWGEOM *lwgeom, double dist)\n{\n\tswitch(TYPE_GETTYPE(lwgeom->type))\n\t{\n\t\tcase LINETYPE:\n\t\t\treturn (LWGEOM *)lwline_segmentize2d((LWLINE *)lwgeom,\n\t\t\t\tdist);\n\t\tcase POLYGONTYPE:\n\t\t\treturn (LWGEOM *)lwpoly_segmentize2d((LWPOLY *)lwgeom,\n\t\t\t\tdist);\n\t\tcase MULTILINETYPE:\n\t\tcase MULTIPOLYGONTYPE:\n\t\tcase COLLECTIONTYPE:\n\t\t\treturn (LWGEOM *)lwcollection_segmentize2d(\n\t\t\t\t(LWCOLLECTION *)lwgeom, dist);\n\n\t\tdefault:\n\t\t\treturn lwgeom_clone(lwgeom);\n\t}\n}\n\nvoid\nlwgeom_longitude_shift(LWGEOM *lwgeom)\n{\n\tint i;\n\tswitch(TYPE_GETTYPE(lwgeom->type))\n\t{\n\t\tLWPOINT *point;\n\t\tLWLINE *line;\n\t\tLWPOLY *poly;\n\t\tLWCOLLECTION *coll;\n\n\t\tcase POINTTYPE:\n\t\t\tpoint = (LWPOINT *)lwgeom;\n\t\t\tptarray_longitude_shift(point->point);\n\t\t\treturn;\n\t\tcase LINETYPE:\n\t\t\tline = (LWLINE *)lwgeom;\n\t\t\tptarray_longitude_shift(line->points);\n\t\t\treturn;\n\t\tcase POLYGONTYPE:\n\t\t\tpoly = (LWPOLY *)lwgeom;\n\t\t\tfor (i=0; i<poly->nrings; i++)\n\t\t\t\tptarray_longitude_shift(poly->rings[i]);\n\t\t\treturn;\n\t\tcase MULTIPOINTTYPE:\n\t\tcase MULTILINETYPE:\n\t\tcase MULTIPOLYGONTYPE:\n\t\tcase COLLECTIONTYPE:\n\t\t\tcoll = (LWCOLLECTION *)lwgeom;\n\t\t\tfor (i=0; i<coll->ngeoms; i++)\n\t\t\t\tlwgeom_longitude_shift(coll->geoms[i]);\n\t\t\treturn;\n\t\tdefault:\n\t\t\tlwerror(\"%s:%d: unsupported geom type: %s\",\n\t\t\t\t__FILE__, __LINE__,\n\t\t\t\tlwgeom_typename(TYPE_GETTYPE(lwgeom->type)));\n\t}\n}\n\n\nint\nlwgeom_contains_subgeoms(int type)\n{\n\t/* Return TRUE if the geometry may contain sub-geometries, i.e. it is a MULTI* or COMPOUNDCURVE */\n\tswitch(type)\n        {\n\t\tcase MULTIPOINTTYPE:\n\t\tcase MULTILINETYPE:\n\t\tcase MULTIPOLYGONTYPE:\n\t\tcase COLLECTIONTYPE:\n\t\tcase COMPOUNDTYPE:\n\t\tcase MULTICURVETYPE:\n\t\tcase MULTISURFACETYPE:\n\t\t\treturn -1;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\treturn 0;\n\t}\n}\n\nvoid lwgeom_free(LWGEOM *lwgeom) {\n\n\tswitch(TYPE_GETTYPE(lwgeom->type))\n\t{\n\t\tcase POINTTYPE:\n\t\t\tlwpoint_free((LWPOINT *)lwgeom);\n\t\t\tbreak;\n\t\tcase LINETYPE:\n\t\t\tlwline_free((LWLINE *)lwgeom);\n\t\t\tbreak;\n\t\tcase POLYGONTYPE:\n\t\t\tlwpoly_free((LWPOLY *)lwgeom);\n\t\t\tbreak;\n\t\tcase MULTIPOINTTYPE:\n\t\t\tlwmpoint_free((LWMPOINT *)lwgeom);\n\t\t\tbreak;\n\t\tcase MULTILINETYPE:\n\t\t\tlwmline_free((LWMLINE *)lwgeom);\n\t\t\tbreak;\n\t\tcase MULTIPOLYGONTYPE:\n\t\t\tlwmpoly_free((LWMPOLY *)lwgeom);\n\t\t\tbreak;\n\t\tcase COLLECTIONTYPE:\n\t\t\tlwcollection_free((LWCOLLECTION *)lwgeom);\n\t\t\tbreak;\n\t}\t\n\treturn;\n\t\n};\n"
  },
  {
    "path": "src/liblwgeom/lwgeom_api.c",
    "content": "\n#include <math.h>\n#include <float.h>\n#include <string.h>\n#include <stdio.h>\n#include <errno.h>\n\n#include \"liblwgeom.h\"\n#include \"wktparse.h\"\n\n/*\n * Lower this to reduce integrity checks\n */\n#define PARANOIA_LEVEL 1\n\n\n\n/**********************************************************************\n * BOX routines\n *\n * returns the float thats very close to the input, but <=\n *  handles the funny differences in float4 and float8 reps.\n **********************************************************************/\n\n\n/*\n * These are taken from glibc\n * some machines do *not* have these functions defined, so we give\n *  an implementation of them here.\n */\ntypedef int int32_tt;\ntypedef unsigned int u_int32_tt;\n\ntypedef union\n{\n  float value;\n  u_int32_tt word;\n} ieee_float_shape_type;\n\n#define GET_FLOAT_WORD(i,d)\t\t\t\\\n\tdo {\t\t\t\t\t\\\n\t\tieee_float_shape_type gf_u;\t\\\n\t\tgf_u.value = (d);\t\t\\\n\t\t(i) = gf_u.word;\t\t\\\n\t} while (0)\n\n\n#define SET_FLOAT_WORD(d,i)\t\t\t\\\n\tdo {\t\t\t\t\t\\\n\t\tieee_float_shape_type sf_u;\t\\\n\t\tsf_u.word = (i);\t\t\\\n\t\t(d) = sf_u.value;\t\t\\\n\t} while (0)\n\n\n/*\n * Returns the next smaller or next larger float\n * from x (in direction of y).\n */\nfloat\nnextafterf_custom(float x, float y)\n{\n        int32_tt hx,hy,ix,iy;\n\n        GET_FLOAT_WORD(hx,x);\n        GET_FLOAT_WORD(hy,y);\n        ix = hx&0x7fffffff;             /* |x| */\n        iy = hy&0x7fffffff;             /* |y| */\n\n        if((ix>0x7f800000) ||   /* x is nan */\n           (iy>0x7f800000))     /* y is nan */\n           return x+y;\n        if(x==y) return y;              /* x=y, return y */\n        if(ix==0) {                             /* x == 0 */\n            SET_FLOAT_WORD(x,(hy&0x80000000)|1);/* return +-minsubnormal */\n            y = x*x;\n            if(y==x) return y; else return x;   /* raise underflow flag */\n        }\n        if(hx>=0) {                             /* x > 0 */\n            if(hx>hy) {                         /* x > y, x -= ulp */\n                hx -= 1;\n            } else {                            /* x < y, x += ulp */\n                hx += 1;\n            }\n        } else {                                /* x < 0 */\n            if(hy>=0||hx>hy){                   /* x < y, x -= ulp */\n                hx -= 1;\n            } else {                            /* x > y, x += ulp */\n                hx += 1;\n            }\n        }\n        hy = hx&0x7f800000;\n        if(hy>=0x7f800000) return x+x;  /* overflow  */\n        if(hy<0x00800000) {             /* underflow */\n            y = x*x;\n            if(y!=x) {          /* raise underflow flag */\n                SET_FLOAT_WORD(y,hx);\n                return y;\n            }\n        }\n        SET_FLOAT_WORD(x,hx);\n        return x;\n}\n\n\nfloat nextDown_f(double d)\n{\n\tfloat result  = d;\n\n\tif ( ((double) result) <=d)\n\t\treturn result;\n\n\treturn nextafterf_custom(result, result - 1000000);\n\n}\n\n/*\n * Returns the float thats very close to the input, but >=.\n * handles the funny differences in float4 and float8 reps.\n */\nfloat\nnextUp_f(double d)\n{\n\tfloat result  = d;\n\n\tif ( ((double) result) >=d)\n\t\treturn result;\n\n\treturn nextafterf_custom(result, result + 1000000);\n}\n\n\n/*\n * Returns the double thats very close to the input, but <.\n * handles the funny differences in float4 and float8 reps.\n */\ndouble\nnextDown_d(float d)\n{\n\tdouble result  = d;\n\n\tif ( result < d)\n\t\treturn result;\n\n\treturn nextafterf_custom(result, result - 1000000);\n}\n\n/*\n * Returns the double thats very close to the input, but >\n * handles the funny differences in float4 and float8 reps.\n */\ndouble\nnextUp_d(float d)\n{\n\tdouble result  = d;\n\n\tif ( result > d)\n\t\treturn result;\n\n\treturn nextafterf_custom(result, result + 1000000);\n}\n\n\n\n/*\n * Convert BOX3D to BOX2D\n * returned box2d is allocated with 'lwalloc'\n */\nBOX2DFLOAT4 *\nbox3d_to_box2df(BOX3D *box)\n{\n\tBOX2DFLOAT4 *result = (BOX2DFLOAT4*) lwalloc(sizeof(BOX2DFLOAT4));\n\n#if PARANOIA_LEVEL > 0\n\tif (box == NULL)\n\t{\n\t\tlwerror(\"box3d_to_box2df got NUL box\");\n\t\treturn NULL;\n\t}\n#endif\n\n\tresult->xmin = nextDown_f(box->xmin);\n\tresult->ymin = nextDown_f(box->ymin);\n\n\tresult->xmax = nextUp_f(box->xmax);\n\tresult->ymax = nextUp_f(box->ymax);\n\n\treturn result;\n}\n\n/*\n * Convert BOX3D to BOX2D using pre-allocated BOX2D\n * returned box2d is allocated with 'lwalloc'\n * return 0 on error (NULL input box)\n */\nint\nbox3d_to_box2df_p(BOX3D *box, BOX2DFLOAT4 *result)\n{\n#if PARANOIA_LEVEL > 0\n\tif (box == NULL)\n\t{\n\t\tlwerror(\"box3d_to_box2df got NUL box\");\n\t\treturn 0;\n\t}\n#endif\n\n\tresult->xmin = nextDown_f(box->xmin);\n\tresult->ymin = nextDown_f(box->ymin);\n\n\tresult->xmax = nextUp_f(box->xmax);\n\tresult->ymax = nextUp_f(box->ymax);\n\n\treturn 1;\n}\n\n\n\n/*\n * Convert BOX2D to BOX3D\n * zmin and zmax are set to NO_Z_VALUE\n */\nBOX3D\nbox2df_to_box3d(BOX2DFLOAT4 *box)\n{\n\tBOX3D result;\n\n#if PARANOIA_LEVEL > 0\n\tif (box == NULL)\n\t\tlwerror(\"box2df_to_box3d got NULL box\");\n#endif\n\n\tresult.xmin = box->xmin;\n\tresult.ymin = box->ymin;\n\n\tresult.xmax = box->xmax;\n\tresult.ymax = box->ymax;\n\n\tresult.zmin = result.zmax = NO_Z_VALUE;\n\n\treturn result;\n}\n\n/*\n * Convert BOX2D to BOX3D, using pre-allocated BOX3D as output\n * Z values are set to NO_Z_VALUE.\n */\nvoid\nbox2df_to_box3d_p(BOX2DFLOAT4 *box, BOX3D *out)\n{\n\tif (box == NULL) return;\n\n\tout->xmin = box->xmin;\n\tout->ymin = box->ymin;\n\n\tout->xmax = box->xmax;\n\tout->ymax = box->ymax;\n\n\tout->zmin = out->zmax = NO_Z_VALUE;\n}\n\n\n\n/*\n * Returns a BOX3D that encloses b1 and b2\n * box3d_union(NULL,A) --> A\n * box3d_union(A,NULL) --> A\n * box3d_union(A,B) --> A union B\n */\nBOX3D *\nbox3d_union(BOX3D *b1, BOX3D *b2)\n{\n\tBOX3D *result;\n\n\tresult = lwalloc(sizeof(BOX3D));\n\n\tif ( (b1 == NULL) && (b2 == NULL) )\n\t{\n\t\treturn NULL;\n\t}\n\n\tif  (b1 == NULL)\n\t{\n\t\t/*return b2 */\n\t\tmemcpy(result, b2, sizeof(BOX3D));\n\t\treturn result;\n\t}\n\tif (b2 == NULL)\n\t{\n\t\t/*return b1 */\n\t\tmemcpy(result, b1, sizeof(BOX3D));\n\t\treturn result;\n\t}\n\n\tif (b1->xmin < b2->xmin)\n\t\tresult->xmin = b1->xmin;\n\telse\n\t\tresult->xmin = b2->xmin;\n\n\tif (b1->ymin < b2->ymin)\n\t\t\tresult->ymin = b1->ymin;\n\telse\n\t\tresult->ymin = b2->ymin;\n\n\n\tif (b1->xmax > b2->xmax)\n\t\tresult->xmax = b1->xmax;\n\telse\n\t\tresult->xmax = b2->xmax;\n\n\tif (b1->ymax > b2->ymax)\n\t\tresult->ymax = b1->ymax;\n\telse\n\t\tresult->ymax = b2->ymax;\n\n\tif (b1->zmax > b2->zmax)\n\t\t\tresult->zmax = b1->zmax;\n\telse\n\t\t\tresult->zmax = b2->zmax;\n\n\tif (b1->zmin > b2->zmin)\n\t\tresult->zmin = b1->zmin;\n\telse\n\t\tresult->zmin = b2->zmin;\n\n\treturn result;\n}\n\n/* Make given ubox a union of b1 and b2 */\nint\nbox3d_union_p(BOX3D *b1, BOX3D *b2, BOX3D *ubox)\n{\n\n        LWDEBUG(2, \"box3d_union_p called: (xmin, xmax), (ymin, ymax), (zmin, zmax)\");\n        LWDEBUGF(4, \"b1: (%.16f, %.16f),(%.16f, %.16f),(%.16f, %.16f)\", b1->xmin, b1->xmax, b1->ymin, b1->ymax, b1->zmin, b1->zmax);\n        LWDEBUGF(4, \"b2: (%.16f, %.16f),(%.16f, %.16f),(%.16f, %.16f)\", b2->xmin, b2->xmax, b2->ymin, b2->ymax, b2->zmin, b2->zmax);\n\n\tif ( (b1 == NULL) && (b2 == NULL) )\n\t{\n\t\treturn 0;\n\t}\n\n\tif  (b1 == NULL)\n\t{\n\t\tmemcpy(ubox, b2, sizeof(BOX3D));\n\t\treturn 1;\n\t}\n\tif (b2 == NULL)\n\t{\n\t\tmemcpy(ubox, b1, sizeof(BOX3D));\n\t\treturn 1;\n\t}\n\n\tif (b1->xmin < b2->xmin)\n\t\tubox->xmin = b1->xmin;\n\telse\n\t\tubox->xmin = b2->xmin;\n\n\tif (b1->ymin < b2->ymin)\n\t\tubox->ymin = b1->ymin;\n\telse\n\t\tubox->ymin = b2->ymin;\n\n\n\tif (b1->xmax > b2->xmax)\n\t\tubox->xmax = b1->xmax;\n\telse\n\t\tubox->xmax = b2->xmax;\n\n\tif (b1->ymax > b2->ymax)\n\t\tubox->ymax = b1->ymax;\n\telse\n\t\tubox->ymax = b2->ymax;\n\n\tif (b1->zmax > b2->zmax)\n\t\tubox->zmax = b1->zmax;\n\telse\n\t\tubox->zmax = b2->zmax;\n\n\tif (b1->zmin < b2->zmin)\n\t\tubox->zmin = b1->zmin;\n\telse\n\t\tubox->zmin = b2->zmin;\n\n\treturn 1;\n}\n\n#if 0 /* UNUSED */\n/*\n * Returns a pointer to internal storage, or NULL\n * if the serialized form does not have a BBOX.\n */\nBOX2DFLOAT4 *\ngetbox2d_internal(uchar *srl)\n{\n\tif (TYPE_HASBBOX(srl[0])) return (BOX2DFLOAT4 *)(srl+1);\n\telse return NULL;\n}\n#endif /* UNUSED */\n\n/*\n * Same as getbox2d, but modifies box instead of returning result on the stack\n */\nint\ngetbox2d_p(uchar *srl, BOX2DFLOAT4 *box)\n{\n\tuchar type = srl[0];\n\tuchar *loc;\n\tBOX3D box3d;\n\n\tLWDEBUG(2, \"getbox2d_p call\");\n\n\tloc = srl+1;\n\n\tif (lwgeom_hasBBOX(type))\n\t{\n\t\t/*woot - this is easy */\n\t\tLWDEBUG(4, \"getbox2d_p: has box\");\n\t\tmemcpy(box, loc, sizeof(BOX2DFLOAT4));\n\t\treturn 1;\n\t}\n\n\tLWDEBUG(4, \"getbox2d_p: has no box - computing\");\n\n\t/* We have to actually compute it! */\n\tif ( ! compute_serialized_box3d_p(srl, &box3d) ) return 0;\n\n\tLWDEBUGF(4, \"getbox2d_p: compute_serialized_box3d returned %p\", box3d);\n\n\tif ( ! box3d_to_box2df_p(&box3d, box) ) return 0;\n\n\tLWDEBUG(4, \"getbox2d_p: box3d converted to box2d\");\n\n\treturn 1;\n}\n\n/************************************************************************\n * POINTARRAY support functions\n *\n * TODO: should be moved to ptarray.c probably\n *\n ************************************************************************/\n\n/*\n * Copies a point from the point array into the parameter point\n * will set point's z=NO_Z_VALUE if pa is 2d\n * will set point's m=NO_M_VALUE if pa is 3d or 2d\n *\n * NOTE: point is a real POINT3D *not* a pointer\n */\nPOINT4D\ngetPoint4d(const POINTARRAY *pa, int n)\n{\n\tPOINT4D result;\n\tgetPoint4d_p(pa, n, &result);\n\treturn result;\n}\n\n/*\n * Copies a point from the point array into the parameter point\n * will set point's z=NO_Z_VALUE  if pa is 2d\n * will set point's m=NO_M_VALUE  if pa is 3d or 2d\n *\n * NOTE: this will modify the point4d pointed to by 'point'.\n */\nint\ngetPoint4d_p(const POINTARRAY *pa, int n, POINT4D *op)\n{\n\tuchar *ptr;\n\tint zmflag;\n\n#if PARANOIA_LEVEL > 0\n\tif ( ! pa ) lwerror(\"getPoint4d_p: NULL pointarray\");\n\n\tif ( (n<0) || (n>=pa->npoints))\n\t{\n\t\tlwerror(\"getPoint4d_p: point offset out of range\");\n\t}\n#endif\n\n        LWDEBUG(4, \"getPoint4d_p called.\");\n\n\t/* Get a pointer to nth point offset and zmflag */\n\tptr=getPoint_internal(pa, n);\n\tzmflag=TYPE_GETZM(pa->dims);\n\n        LWDEBUGF(4, \"ptr %p, zmflag %d\", ptr, zmflag);\n\n\tswitch (zmflag)\n\t{\n\t\tcase 0: /* 2d  */\n\t\t\tmemcpy(op, ptr, sizeof(POINT2D));\n\t\t\top->m=NO_M_VALUE;\n\t\t\top->z=NO_Z_VALUE;\n\t\t\tbreak;\n\n\t\tcase 3: /* ZM */\n\t\t\tmemcpy(op, ptr, sizeof(POINT4D));\n\t\t\tbreak;\n\n\t\tcase 2: /* Z */\n\t\t\tmemcpy(op, ptr, sizeof(POINT3DZ));\n\t\t\top->m=NO_M_VALUE;\n\t\t\tbreak;\n\n\t\tcase 1: /* M */\n\t\t\tmemcpy(op, ptr, sizeof(POINT3DM));\n\t\t\top->m=op->z; /* we use Z as temporary storage */\n\t\t\top->z=NO_Z_VALUE;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tlwerror(\"Unknown ZM flag ??\");\n\t}\n\treturn 1;\n\n}\n\n\n\n/*\n * Copy a point from the point array into the parameter point\n * will set point's z=NO_Z_VALUE if pa is 2d\n * NOTE: point is a real POINT3DZ *not* a pointer\n */\nPOINT3DZ\ngetPoint3dz(const POINTARRAY *pa, int n)\n{\n\tPOINT3DZ result;\n\tgetPoint3dz_p(pa, n, &result);\n\treturn result;\n}\n\n/*\n * Copy a point from the point array into the parameter point\n * will set point's z=NO_Z_VALUE if pa is 2d\n *\n * NOTE: point is a real POINT3DZ *not* a pointer\n */\nPOINT3DM\ngetPoint3dm(const POINTARRAY *pa, int n)\n{\n\tPOINT3DM result;\n\tgetPoint3dm_p(pa, n, &result);\n\treturn result;\n}\n\n/*\n * Copy a point from the point array into the parameter point\n * will set point's z=NO_Z_VALUE if pa is 2d\n * \n * NOTE: this will modify the point3dz pointed to by 'point'.\n */\nint\ngetPoint3dz_p(const POINTARRAY *pa, int n, POINT3DZ *op)\n{\n\tuchar *ptr;\n\n#if PARANOIA_LEVEL > 0\n\tif ( ! pa ) return 0;\n\n\tif ( (n<0) || (n>=pa->npoints))\n\t{\n\t\tLWDEBUGF(4, \"%d out of numpoint range (%d)\", n, pa->npoints);\n\t\treturn 0; /*error */\n\t}\n#endif\n\n\tLWDEBUGF(2, \"getPoint3dz_p called on array of %d-dimensions / %u pts\",\n\t\tTYPE_NDIMS(pa->dims), pa->npoints);\n\n\t/* Get a pointer to nth point offset */\n\tptr=getPoint_internal(pa, n);\n\n\t/*\n\t * if input POINTARRAY has the Z, it is always\n\t * at third position so make a single copy\n\t */\n\tif ( TYPE_HASZ(pa->dims) )\n\t{\n\t\tmemcpy(op, ptr, sizeof(POINT3DZ));\n\t}\n\n\t/*\n\t * Otherwise copy the 2d part and initialize\n\t * Z to NO_Z_VALUE\n\t */\n\telse\n\t{\n\t\tmemcpy(op, ptr, sizeof(POINT2D));\n\t\top->z=NO_Z_VALUE;\n\t}\n\n\treturn 1;\n\n}\n\n/*\n * Copy a point from the point array into the parameter point\n * will set point's m=NO_Z_VALUE if pa has no M\n * \n * NOTE: this will modify the point3dm pointed to by 'point'.\n */\nint\ngetPoint3dm_p(const POINTARRAY *pa, int n, POINT3DM *op)\n{\n\tuchar *ptr;\n\tint zmflag;\n\n#if PARANOIA_LEVEL > 0\n\tif ( ! pa ) return 0;\n\n\tif ( (n<0) || (n>=pa->npoints))\n\t{\n\t\tlwerror(\"%d out of numpoint range (%d)\", n, pa->npoints);\n\t\treturn 0; /*error */\n\t}\n#endif \n\n\tLWDEBUGF(2, \"getPoint3dm_p(%d) called on array of %d-dimensions / %u pts\",\n\t\tn, TYPE_NDIMS(pa->dims), pa->npoints);\n\n\n\t/* Get a pointer to nth point offset and zmflag */\n\tptr=getPoint_internal(pa, n);\n\tzmflag=TYPE_GETZM(pa->dims);\n\n\t/*\n\t * if input POINTARRAY has the M and NO Z,\n\t * we can issue a single memcpy\n\t */\n\tif ( zmflag == 1 )\n\t{\n\t\tmemcpy(op, ptr, sizeof(POINT3DM));\n\t\treturn 1;\n\t}\n\n\t/*\n\t * Otherwise copy the 2d part and \n\t * initialize M to NO_M_VALUE\n\t */\n\tmemcpy(op, ptr, sizeof(POINT2D));\n\n\t/*\n\t * Then, if input has Z skip it and\n\t * copy next double, otherwise initialize\n\t * M to NO_M_VALUE\n\t */\n\tif ( zmflag == 3 )\n\t{\n\t\tptr+=sizeof(POINT3DZ);\n\t\tmemcpy(&(op->m), ptr, sizeof(double));\n\t}\n\telse\n\t{\n\t\top->m=NO_M_VALUE;\n\t}\n\n\treturn 1;\n}\n\n\n/*\n * Copy a point from the point array into the parameter point\n * z value (if present) is not returned.\n *\n * NOTE: point is a real POINT2D *not* a pointer\n */\nPOINT2D\ngetPoint2d(const POINTARRAY *pa, int n)\n{\n\tPOINT2D result;\n\tgetPoint2d_p(pa, n, &result);\n\treturn result;\n}\n\n/*\n * Copy a point from the point array into the parameter point\n * z value (if present) is not returned.\n *\n * NOTE: this will modify the point2d pointed to by 'point'.\n */\nint\ngetPoint2d_p(const POINTARRAY *pa, int n, POINT2D *point)\n{\n#if PARANOIA_LEVEL > 0\n\tif ( ! pa ) return 0;\n\n\tif ( (n<0) || (n>=pa->npoints))\n\t{\n\t\tlwerror(\"getPoint2d_p: point offset out of range\");\n\t\treturn 0; /*error */\n\t}\n#endif\n\n\t/* this does x,y */\n\tmemcpy(point, getPoint_internal(pa, n), sizeof(POINT2D));\n\treturn 1;\n}\n\n/*\n * set point N to the given value\n * NOTE that the pointarray can be of any\n * dimension, the appropriate ordinate values\n * will be extracted from it\n *\n */\nvoid\nsetPoint4d(POINTARRAY *pa, int n, POINT4D *p4d)\n{\n\tuchar *ptr=getPoint_internal(pa, n);\n\tswitch ( TYPE_GETZM(pa->dims) )\n\t{\n\t\tcase 3:\n\t\t\tmemcpy(ptr, p4d, sizeof(POINT4D));\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tmemcpy(ptr, p4d, sizeof(POINT3DZ));\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tmemcpy(ptr, p4d, sizeof(POINT2D));\n\t\t\tptr+=sizeof(POINT2D);\n\t\t\tmemcpy(ptr, &(p4d->m), sizeof(double));\n\t\t\tbreak;\n\t\tcase 0:\n\t\t\tmemcpy(ptr, p4d, sizeof(POINT2D));\n\t\t\tbreak;\n\t}\n}\n\n\n/*\n * Get a pointer to nth point of a POINTARRAY.\n * You cannot safely cast this to a real POINT, due to memory alignment\n * constraints. Use getPoint*_p for that.\n */\nuchar *\ngetPoint_internal(const POINTARRAY *pa, int n)\n{\n\tint size;\n\n#if PARANOIA_LEVEL > 0\n\tif ( pa == NULL ) {\n\t\tlwerror(\"getPoint got NULL pointarray\");\n\t\treturn NULL;\n\t}\n\n\tif ( (n<0) || (n>=pa->npoints))\n\t{\n\t\treturn NULL; /*error */\n\t}\n#endif\n\n\tsize = pointArray_ptsize(pa);\n\n\treturn &(pa->serialized_pointlist[size*n]);\n}\n\n\n\n/*\n * Constructs a POINTARRAY.\n *\n * NOTE: points is *not* copied, so be careful about modification\n * (can be aligned/missaligned).\n *\n * NOTE: ndims is descriptive - it describes what type of data 'points'\n *       points to.  No data conversion is done.\n */\nPOINTARRAY *\npointArray_construct(uchar *points, char hasz, char hasm, uint32 npoints)\n{\n\tPOINTARRAY  *pa;\n\t\n\tLWDEBUG(2, \"pointArray_construct called.\");\n\n\tpa = (POINTARRAY*)lwalloc(sizeof(POINTARRAY));\n\n\tpa->dims = 0;\n\tTYPE_SETZM(pa->dims, hasz?1:0, hasm?1:0);\n\tpa->npoints = npoints;\n\n\tpa->serialized_pointlist = points;\n\n\tLWDEBUGF(4, \"pointArray_construct returning %p\", pa);\n\n\treturn pa;\n}\n\n\n/*\n * Size of point represeneted in the POINTARRAY\n * 16 for 2d, 24 for 3d, 32 for 4d\n */\nint\npointArray_ptsize(const POINTARRAY *pa)\n{\n\tLWDEBUGF(2, \"pointArray_ptsize: TYPE_NDIMS(pa->dims)=%x\",TYPE_NDIMS(pa->dims));\n\n\treturn sizeof(double)*TYPE_NDIMS(pa->dims);\n}\n\n\n/***************************************************************************\n * Basic type handling\n ***************************************************************************/\n\n\n/* Returns true if this type says it has an SRID (S bit set) */\nchar\nlwgeom_hasSRID(uchar type)\n{\n\treturn TYPE_HASSRID(type);\n}\n\n/* Returns either 2,3, or 4 -- 2=2D, 3=3D, 4=4D */\nint\nlwgeom_ndims(uchar type)\n{\n\treturn TYPE_NDIMS(type);\n}\n\n/* has M ? */\nint lwgeom_hasM(uchar type)\n{\n\treturn  ( (type & 0x10) >>4);\n}\n\n/* has Z ? */\nint lwgeom_hasZ(uchar type)\n{\n\treturn  ( (type & 0x20) >>5);\n}\n\n\n/* get base type (ie. POLYGONTYPE) */\nint\nlwgeom_getType(uchar type)\n{\n        LWDEBUGF(2, \"lwgeom_getType %d\", type);\n\n\treturn (type & 0x0F);\n}\n\n\n/* Construct a type (hasBOX=false) */\nuchar\nlwgeom_makeType(char hasz, char hasm, char hasSRID, int type)\n{\n\treturn lwgeom_makeType_full(hasz, hasm, hasSRID, type, 0);\n}\n\n/*\n * Construct a type\n * TODO: needs to be expanded to accept explicit MZ type\n */\nuchar\nlwgeom_makeType_full(char hasz, char hasm, char hasSRID, int type, char hasBBOX)\n{\n\tuchar result = (char)type;\n\n\tTYPE_SETZM(result, hasz, hasm);\n\tTYPE_SETHASSRID(result, hasSRID);\n\tTYPE_SETHASBBOX(result, hasBBOX);\n\n\treturn result;\n}\n\n/* Returns true if there's a bbox in this LWGEOM (B bit set) */\nchar\nlwgeom_hasBBOX(uchar type)\n{\n\treturn TYPE_HASBBOX(type);\n}\n\n/*****************************************************************************\n * Basic sub-geometry types\n *****************************************************************************/\n\n/* handle missaligned unsigned int32 data */\nuint32\nlw_get_uint32(const uchar *loc)\n{\n\tuint32 result;\n\n\tmemcpy(&result, loc, sizeof(uint32));\n\treturn result;\n}\n\n/* handle missaligned signed int32 data */\nint32\nlw_get_int32(const uchar *loc)\n{\n\tint32 result;\n\n\tmemcpy(&result,loc, sizeof(int32));\n\treturn result;\n}\n\n\n/*************************************************************************\n *\n * Multi-geometry support\n *\n * Note - for a simple type (ie. point), this will have\n * sub_geom[0] = serialized_form.\n *\n * For multi-geomtries sub_geom[0] will be a few bytes\n * into the serialized form.\n *\n * This function just computes the length of each sub-object and\n * pre-caches this info.\n *\n * For a geometry collection of multi* geometries, you can inspect\n * the sub-components\n * as well.\n */\nLWGEOM_INSPECTED *\nlwgeom_inspect(const uchar *serialized_form)\n{\n\tLWGEOM_INSPECTED *result = lwalloc(sizeof(LWGEOM_INSPECTED));\n\tuchar typefl = (uchar)serialized_form[0];\n\tuchar type;\n\tuchar **sub_geoms;\n\tconst uchar *loc;\n\tint \tt;\n\n\tLWDEBUGF(2, \"lwgeom_inspect: serialized@%p\", serialized_form);\n\n\tif (serialized_form == NULL)\n\t\treturn NULL;\n\n\tresult->serialized_form = serialized_form; \n\tresult->type = (uchar) serialized_form[0];\n\tresult->SRID = -1; /* assume */\n\n\ttype = lwgeom_getType(typefl);\n\n\tloc = serialized_form+1;\n\n\tif ( lwgeom_hasBBOX(typefl) )\n\t{\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t}\n\n\tif ( lwgeom_hasSRID(typefl) )\n\t{\n\t\tresult->SRID = lw_get_int32(loc);\n\t\tloc += 4;\n\t}\n\n\tif ( (type==POINTTYPE) || (type==LINETYPE) || (type==POLYGONTYPE) || (type == CIRCSTRINGTYPE))\n\t{\n\t\t/* simple geometry (point/line/polygon/circstring)-- not multi! */\n\t\tresult->ngeometries = 1;\n\t\tsub_geoms = (uchar**) lwalloc(sizeof(char*));\n\t\tsub_geoms[0] = (uchar *)serialized_form;\n\t\tresult->sub_geoms = (uchar **)sub_geoms;\n\t\treturn result;\n\t}\n\n\t/* its a GeometryCollection or multi* geometry */\n\n\tresult->ngeometries = lw_get_uint32(loc);\n\tloc +=4;\n\n\tLWDEBUGF(3, \"lwgeom_inspect: geometry is a collection of %d elements\",\n\t\tresult->ngeometries);\n\n\tif ( ! result->ngeometries ) return result;\n\n\tsub_geoms = lwalloc(sizeof(uchar*) * result->ngeometries );\n\tresult->sub_geoms = sub_geoms;\n\tsub_geoms[0] = (uchar *)loc;\n\n\tLWDEBUGF(3, \"subgeom[0] @ %p (+%d)\", sub_geoms[0], sub_geoms[0]-serialized_form);\n\n\tfor (t=1;t<result->ngeometries; t++)\n\t{\n\t\t/* -1 = entire object */\n\t\tint sub_length = lwgeom_size_subgeom(sub_geoms[t-1], -1);\n\t\tsub_geoms[t] = sub_geoms[t-1] + sub_length;\n                \n\t\tLWDEBUGF(3, \"subgeom[%d] @ %p (+%d)\",\n\t\t\tt, sub_geoms[t], sub_geoms[0]-serialized_form);\n\t}\n\n\treturn result;\n\n}\n\n\n/*\n * 1st geometry has geom_number = 0\n * if the actual sub-geometry isnt a POINT, null is returned (see _gettype()).\n * if there arent enough geometries, return null.\n * this is fine to call on a point (with geom_num=0),\n * multipoint or geometrycollection\n */\nLWPOINT *\nlwgeom_getpoint(uchar *serialized_form, int geom_number)\n{\n\tint type = lwgeom_getType((uchar)serialized_form[0]);\n\tuchar *sub_geom;\n\n\tif ((type == POINTTYPE)  && (geom_number == 0))\n\t{\n\t\t/* Be nice and do as they want instead of what they say */\n\t\treturn lwpoint_deserialize(serialized_form);\n\t}\n\n\tif ((type != MULTIPOINTTYPE) && (type != COLLECTIONTYPE) )\n\t\treturn NULL;\n\n\tsub_geom = lwgeom_getsubgeometry(serialized_form, geom_number);\n\tif (sub_geom == NULL)\n\t\treturn NULL;\n\n\ttype = lwgeom_getType(sub_geom[0]);\n\tif (type != POINTTYPE)\n\t\treturn NULL;\n\n\treturn lwpoint_deserialize(sub_geom);\n}\n\n/*\n * 1st geometry has geom_number = 0\n * if the actual sub-geometry isnt a POINT, null is returned (see _gettype()).\n * if there arent enough geometries, return null.\n * this is fine to call on a point (with geom_num=0), multipoint\n * or geometrycollection\n */\nLWPOINT *lwgeom_getpoint_inspected(LWGEOM_INSPECTED *inspected, int geom_number)\n{\n\tuchar *sub_geom;\n\tuchar type;\n\n\tsub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);\n\n\tif (sub_geom == NULL) return NULL;\n\n\ttype = lwgeom_getType(sub_geom[0]);\n\tif (type != POINTTYPE) return NULL;\n\n\treturn lwpoint_deserialize(sub_geom);\n}\n\n\n/*\n * 1st geometry has geom_number = 0\n * if the actual geometry isnt a LINE, null is returned (see _gettype()).\n * if there arent enough geometries, return null.\n * this is fine to call on a line, multiline or geometrycollection\n */\nLWLINE *\nlwgeom_getline(uchar *serialized_form, int geom_number)\n{\n\tuchar type = lwgeom_getType( (uchar) serialized_form[0]);\n\tuchar *sub_geom;\n\n\tif ((type == LINETYPE)  && (geom_number == 0))\n\t{\n\t\t/* be nice and do as they want instead of what they say */\n\t\treturn lwline_deserialize(serialized_form);\n\t}\n\n\tif ((type != MULTILINETYPE) && (type != COLLECTIONTYPE) )\n\t\treturn NULL;\n\n\tsub_geom = lwgeom_getsubgeometry(serialized_form, geom_number);\n\tif (sub_geom == NULL) return NULL;\n\n\ttype = lwgeom_getType((uchar) sub_geom[0]);\n\tif (type != LINETYPE) return NULL;\n\n\treturn lwline_deserialize(sub_geom);\n}\n\n/*\n * 1st geometry has geom_number = 0\n * if the actual geometry isnt a LINE, null is returned (see _gettype()).\n * if there arent enough geometries, return null.\n * this is fine to call on a line, multiline or geometrycollection\n */\nLWLINE *\nlwgeom_getline_inspected(LWGEOM_INSPECTED *inspected, int geom_number)\n{\n\tuchar *sub_geom;\n\tuchar type;\n\n\tsub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);\n\n\tif (sub_geom == NULL) return NULL;\n\n\ttype = lwgeom_getType((uchar) sub_geom[0]);\n\tif (type != LINETYPE) return NULL;\n\n\treturn lwline_deserialize(sub_geom);\n}\n\n/*\n * 1st geometry has geom_number = 0\n * if the actual geometry isnt a POLYGON, null is returned (see _gettype()).\n * if there arent enough geometries, return null.\n * this is fine to call on a polygon, multipolygon or geometrycollection\n */\nLWPOLY *\nlwgeom_getpoly(uchar *serialized_form, int geom_number)\n{\n\tuchar type = lwgeom_getType((uchar)serialized_form[0]);\n\tuchar *sub_geom;\n\n\tif ((type == POLYGONTYPE)  && (geom_number == 0))\n\t{\n\t\t/* Be nice and do as they want instead of what they say */\n\t\treturn lwpoly_deserialize(serialized_form);\n\t}\n\n\tif ((type != MULTIPOLYGONTYPE) && (type != COLLECTIONTYPE) )\n\t\treturn NULL;\n\n\tsub_geom = lwgeom_getsubgeometry(serialized_form, geom_number);\n\tif (sub_geom == NULL) return NULL;\n\n\ttype = lwgeom_getType(sub_geom[0]);\n\tif (type != POLYGONTYPE) return NULL;\n\n\treturn lwpoly_deserialize(sub_geom);\n}\n\n/*\n * 1st geometry has geom_number = 0\n * if the actual geometry isnt a POLYGON, null is returned (see _gettype()).\n * if there arent enough geometries, return null.\n * this is fine to call on a polygon, multipolygon or geometrycollection\n */\nLWPOLY *\nlwgeom_getpoly_inspected(LWGEOM_INSPECTED *inspected, int geom_number)\n{\n\tuchar *sub_geom;\n\tuchar type;\n\n\tsub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);\n\n\tif (sub_geom == NULL) return NULL;\n\n\ttype = lwgeom_getType(sub_geom[0]);\n\tif (type != POLYGONTYPE) return NULL;\n\n\treturn lwpoly_deserialize(sub_geom);\n}\n\n/*\n * 1st geometry has geom_number = 0\n * if the actual geometry isnt a CIRCULARSTRING, null is returned (see _gettype()).\n * if there arent enough geometries, return null.\n * this is fine to call on a circularstring\n */\nLWCIRCSTRING *\nlwgeom_getcircstring_inspected(LWGEOM_INSPECTED *inspected, int geom_number)\n{\n\tuchar *sub_geom;\n\tuchar type;\n\n\tsub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);\n\n\tif (sub_geom == NULL) return NULL;\n\n\ttype = lwgeom_getType(sub_geom[0]);\n\tif (type != CIRCSTRINGTYPE) return NULL;\n\n\treturn lwcircstring_deserialize(sub_geom);\n}\n\n/*\n * 1st geometry has geom_number = 0\n * if there arent enough geometries, return null.\n */\nLWGEOM *lwgeom_getgeom_inspected(LWGEOM_INSPECTED *inspected, int geom_number)\n{\n\tuchar *sub_geom;\n\tuchar type;\n\n\tsub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);\n\n\tif (sub_geom == NULL) return NULL;\n\n\ttype = lwgeom_getType(sub_geom[0]);\n\n\treturn lwgeom_deserialize(sub_geom);\n}\n\n\n/*\n * This gets the serialized form of a sub-geometry\n *\n * 1st geometry has geom_number = 0\n * if this isnt a multi* geometry, and geom_number ==0 then it returns\n * itself.\n *\n * Returns null on problems.\n *\n * In the future this is how you would access a muli* portion of a\n * geometry collection.\n *    GEOMETRYCOLLECTION(MULTIPOINT(0 0, 1 1), LINESTRING(0 0, 1 1))\n *   ie. lwgeom_getpoint( lwgeom_getsubgeometry( serialized, 0), 1)\n *           --> POINT(1 1)\n *\n * You can inspect the sub-geometry as well if you wish.\n *\n */\nuchar *\nlwgeom_getsubgeometry(const uchar *serialized_form, int geom_number)\n{\n\tuchar *result;\n\t/*major cheat!! */\n\tLWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized_form);\n\n\tresult = lwgeom_getsubgeometry_inspected(inspected, geom_number);\n\tlwinspected_release(inspected);\n\treturn result;\n}\n\nuchar *\nlwgeom_getsubgeometry_inspected(LWGEOM_INSPECTED *inspected, int geom_number)\n{\n\tif ((geom_number <0) || (geom_number >= inspected->ngeometries) )\n\t{\n\t\tlwerror(\"lwgeom_getsubgeometry_inspected: geom_number out of range\");\n\t\treturn NULL;\n\t}\n\n\treturn inspected->sub_geoms[geom_number];\n}\n\n\n/*\n * 1st geometry has geom_number = 0\n *  use geom_number = -1 to find the actual type of the serialized form.\n *    ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, -1)\n *                 --> multipoint\n *   ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, 0)\n *                 --> point\n * gets the 8bit type of the geometry at location geom_number\n */\nuchar\nlwgeom_getsubtype(uchar *serialized_form, int geom_number)\n{\n\tchar  result;\n\t/*major cheat!! */\n\tLWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized_form);\n\n\tresult = lwgeom_getsubtype_inspected(inspected, geom_number);\n\tlwinspected_release(inspected);\n\treturn result;\n}\n\nuchar\nlwgeom_getsubtype_inspected(LWGEOM_INSPECTED *inspected, int geom_number)\n{\n\tif ((geom_number <0) || (geom_number >= inspected->ngeometries) )\n\t\treturn 99;\n\n\treturn inspected->sub_geoms[geom_number][0]; /* 1st byte is type */\n}\n\n\n/*\n * How many sub-geometries are there?\n * for point,line,polygon will return 1.\n */\nint\nlwgeom_getnumgeometries(uchar *serialized_form)\n{\n\tuchar type = lwgeom_getType((uchar)serialized_form[0]);\n\tuchar *loc;\n\n\tif ( (type==POINTTYPE) || (type==LINETYPE) || (type==POLYGONTYPE) ||\n            (type==CIRCSTRINGTYPE) || (type==COMPOUNDTYPE) || (type==CURVEPOLYTYPE) )\n\t{\n\t\treturn 1;\n\t}\n\n\tloc = serialized_form+1;\n\n\tif (lwgeom_hasBBOX((uchar) serialized_form[0]))\n\t{\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t}\n\n\tif (lwgeom_hasSRID((uchar) serialized_form[0]) )\n\t{\n\t\tloc += 4;\n\t}\n\t/* its a GeometryCollection or multi* geometry */\n\treturn lw_get_uint32(loc);\n}\n\n/*\n * How many sub-geometries are there?\n * for point,line,polygon will return 1.\n */\nint\nlwgeom_getnumgeometries_inspected(LWGEOM_INSPECTED *inspected)\n{\n\treturn inspected->ngeometries;\n}\n\n\n/*\n * Set finalType to COLLECTIONTYPE or 0 (0 means choose a best type)\n *   (ie. give it 2 points and ask it to be a multipoint)\n *  use SRID=-1 for unknown SRID  (will have 8bit type's S = 0)\n * all subgeometries must have the same SRID\n * if you want to construct an inspected, call this then inspect the result...\n */\nuchar *\nlwgeom_serialized_construct(int SRID, int finalType, char hasz, char hasm,\n\tint nsubgeometries, uchar **serialized_subs)\n{\n\tuint32 *lengths;\n\tint t;\n\tint total_length = 0;\n\tchar type = (char)-1;\n\tchar this_type = -1;\n\tuchar *result;\n\tuchar *loc;\n\n\tif (nsubgeometries == 0)\n\t\treturn lwgeom_constructempty(SRID, hasz, hasm);\n\n\tlengths = lwalloc(sizeof(int32) * nsubgeometries);\n\n\tfor (t=0;t<nsubgeometries;t++)\n\t{\n\t\tlengths[t] = lwgeom_size_subgeom(serialized_subs[t],-1);\n\t\ttotal_length += lengths[t];\n\t\tthis_type = lwgeom_getType((uchar) (serialized_subs[t][0]));\n\t\tif (type == (char)-1)\n\t\t{\n\t\t\ttype = this_type;\n\t\t}\n\t\telse if (type == COLLECTIONTYPE)\n\t\t{\n\t\t\t\t/* still a collection type... */\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( (this_type == MULTIPOINTTYPE) || (this_type == MULTILINETYPE)  || (this_type == MULTIPOLYGONTYPE) || (this_type == COLLECTIONTYPE) )\n\t\t\t{\n\t\t\t\ttype = COLLECTIONTYPE;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ( (this_type == POINTTYPE)  && (type==POINTTYPE) )\n\t\t\t\t\ttype=MULTIPOINTTYPE;\n\t\t\t\telse if ( (this_type == LINETYPE)  && (type==LINETYPE) )\n\t\t\t\t\ttype=MULTILINETYPE;\n\t\t\t\telse if ( (this_type == POLYGONTYPE)  && (type==POLYGONTYPE) )\n\t\t\t\t\ttype=MULTIPOLYGONTYPE;\n\t\t\t\telse if ( (this_type == POLYGONTYPE)  && (type==MULTIPOLYGONTYPE) )\n\t\t\t\t\t; /* nop */\n\t\t\t\telse if ( (this_type == LINETYPE)  && (type==MULTILINETYPE) )\n\t\t\t\t\t; /* nop */\n\t\t\t\telse if ( (this_type == POINTTYPE)  && (type==MULTIPOINTTYPE) )\n\t\t\t\t\t; /* nop */\n\t\t\t\telse\n\t\t\t\t\ttype = COLLECTIONTYPE;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (type == POINTTYPE)\n\t\ttype = MULTIPOINTTYPE;\n\tif (type == LINETYPE)\n\t\ttype = MULTILINETYPE;\n\tif (type == POINTTYPE)\n\t\ttype = MULTIPOINTTYPE;\n\n\tif (finalType == COLLECTIONTYPE)\n\t\ttype = COLLECTIONTYPE;\n\n\t/* now we have a multi* or GEOMETRYCOLLECTION, let's serialize it */\n\n\tif (SRID != -1)\n\t\ttotal_length +=4; /* space for SRID */\n\n\ttotal_length +=1 ;   /* main type; */\n\ttotal_length +=4 ;   /* nsubgeometries */\n\n\tresult = lwalloc(total_length);\n\tresult[0] = (uchar) lwgeom_makeType(hasz, hasm, SRID != -1,  type);\n\tif (SRID != -1)\n\t{\n\t\tmemcpy(&result[1],&SRID,4);\n\t\tloc = result+5;\n\t}\n\telse\n\t\tloc = result+1;\n\n\tmemcpy(loc,&nsubgeometries,4);\n\tloc +=4;\n\n\tfor (t=0;t<nsubgeometries;t++)\n\t{\n\t\tmemcpy(loc, serialized_subs[t], lengths[t] );\n\t\tloc += lengths[t] ;\n\t}\n\n\tlwfree(lengths);\n\treturn result;\n}\n\n\n/*\n * Construct the empty geometry (GEOMETRYCOLLECTION(EMPTY)).\n *\n * Returns serialized form\n */\nuchar *\nlwgeom_constructempty(int SRID, char hasz, char hasm)\n{\n\tint size = 0;\n\tuchar *result;\n\tint ngeoms = 0;\n\tuchar *loc;\n\n\tif (SRID != -1)\n\t\tsize +=4;\n\n\tsize += 5;\n\n\tresult = lwalloc(size);\n\n\tresult[0] = lwgeom_makeType(hasz, hasm, SRID != -1,  COLLECTIONTYPE);\n\tif (SRID != -1)\n\t{\n\t\tmemcpy(&result[1],&SRID,4);\n\t\tloc = result+5;\n\t}\n\telse\n\t\tloc = result+1;\n\n\tmemcpy(loc,&ngeoms,4);\n\treturn result;\n}\n\nsize_t\nlwgeom_empty_length(int SRID)\n{\n\tint size = 5;\n\tif ( SRID != 1 ) size += 4;\n\treturn size;\n}\n\n/*\n * Construct the empty geometry (GEOMETRYCOLLECTION(EMPTY))\n * writing it into the provided buffer.\n */\nvoid\nlwgeom_constructempty_buf(int SRID, char hasz, char hasm,\n\tuchar *buf, size_t *retsize)\n{\n\tint ngeoms = 0;\n\n\tbuf[0] =(uchar) lwgeom_makeType( hasz, hasm, SRID != -1,  COLLECTIONTYPE);\n\tif (SRID != -1)\n\t{\n\t\tmemcpy(&buf[1],&SRID,4);\n\t\tbuf += 5;\n\t}\n\telse\n\t\tbuf += 1;\n\n\tmemcpy(buf, &ngeoms, 4);\n\n\tif (retsize) *retsize = lwgeom_empty_length(SRID);\n}\n\n/*\n * helper function (not for general use)\n * find the size a geometry (or a sub-geometry)\n * 1st geometry has geom_number = 0\n *  use geom_number = -1 to find the actual type of the serialized form.\n *    ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, -1)\n *                 --> size of the multipoint\n *   ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, 0)\n *         --> size of the point\n * take a geometry, and find its length\n */\nsize_t\nlwgeom_size(const uchar *serialized_form)\n{\n\tuchar type = lwgeom_getType((uchar) serialized_form[0]);\n\tint t;\n\tconst uchar *loc;\n\tuint32 ngeoms;\n\tint sub_size;\n\tint result = 1; /* type */\n\n\tLWDEBUG(2, \"lwgeom_size called\");\n\n\tif (type == POINTTYPE)\n\t{\n\t\tLWDEBUG(3, \"lwgeom_size: is a point\");\n\n\t\treturn lwgeom_size_point(serialized_form);\n\t}\n\telse if (type == LINETYPE)\n\t{\n\t\tLWDEBUG(3, \"lwgeom_size: is a line\");\n\n\t\treturn lwgeom_size_line(serialized_form);\n\t}\n        else if(type == CIRCSTRINGTYPE)\n        {\n                LWDEBUG(3, \"lwgeom_size: is a circularstring\");\n\n                return lwgeom_size_circstring(serialized_form);\n        }\n\telse if (type == POLYGONTYPE)\n\t{\n\t\tLWDEBUG(3, \"lwgeom_size: is a polygon\");\n\n\t\treturn lwgeom_size_poly(serialized_form);\n\t} \n        else if (type == COMPOUNDTYPE)\n        {\n                LWDEBUG(3, \"lwgeom_size: is a compound curve\");\n        }\n\n\tif ( type == 0 )\n\t{\n\t\tlwerror(\"lwgeom_size called with unknown-typed serialized geometry\");\n\t\treturn 0;\n\t}\n\n\t/*\n\t * Handle all the multi* and geometrycollections the same\n\t *\n\t * NOTE: for a geometry collection of GC of GC of GC we will\n\t *       be recursing...\n\t */\n\n\tLWDEBUGF(3, \"lwgeom_size called on a geoemtry with type %d\", type);\n\n\tloc = serialized_form+1;\n\n\tif (lwgeom_hasBBOX((uchar) serialized_form[0]))\n\t{\n\t\tLWDEBUG(3, \"lwgeom_size: has bbox\");\n\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t\tresult +=sizeof(BOX2DFLOAT4);\n\t}\n\n\tif (lwgeom_hasSRID( (uchar) serialized_form[0]) )\n\t{\n\t\tLWDEBUG(3, \"lwgeom_size: has srid\");\n\n\t\tresult +=4;\n\t\tloc +=4;\n\t}\n\n\n\tngeoms = lw_get_uint32(loc);\n\tloc +=4;\n\tresult += 4; /* numgeoms */\n\n\tLWDEBUGF(3, \"lwgeom_size called on a geoemtry with %d elems (result so far: %d)\", ngeoms, result);\n\n\tfor (t=0;t<ngeoms;t++)\n\t{\n\t\tsub_size = lwgeom_size(loc);\n\n\t\tLWDEBUGF(3, \" subsize %d\", sub_size);\n\n\t\tloc += sub_size;\n\t\tresult += sub_size;\n\t}\n\n\tLWDEBUGF(3, \"lwgeom_size returning %d\", result);\n\n\treturn result;\n}\n\nsize_t\nlwgeom_size_subgeom(const uchar *serialized_form, int geom_number)\n{\n\tif (geom_number == -1)\n\t{\n\t\treturn lwgeom_size(serialized_form);\n\t}\n\treturn lwgeom_size( lwgeom_getsubgeometry(serialized_form,geom_number));\n}\n\n\n\nint\nlwgeom_size_inspected(const LWGEOM_INSPECTED *inspected, int geom_number)\n{\n\treturn lwgeom_size(inspected->sub_geoms[geom_number]);\n}\n\nint\ncompute_serialized_box3d_p(uchar *srl, BOX3D *out)\n{\n\tBOX3D *box = compute_serialized_box3d(srl);\n\tif ( ! box ) return 0;\n\tout->xmin = box->xmin;\n\tout->ymin = box->ymin;\n\tout->zmin = box->zmin;\n\tout->xmax = box->xmax;\n\tout->ymax = box->ymax;\n\tout->zmax = box->zmax;\n\tlwfree(box);\n\n\treturn 1;\n}\n\n/*\n * Compute bounding box of a serialized LWGEOM, even if it is\n * already cached. The computed BOX2DFLOAT4 is stored at\n * the given location, the function returns 0 is the geometry\n * does not have a bounding box (EMPTY GEOM)\n */\nint\ncompute_serialized_box2d_p(uchar *srl, BOX2DFLOAT4 *out)\n{\n\t  BOX3D *result = compute_serialized_box3d(srl);\n\t  if ( ! result ) return 0;\n\t  out->xmin = result->xmin;\n\t  out->xmax = result->xmax;\n\t  out->ymin = result->ymin;\n\t  out->ymax = result->ymax;\n\t  lwfree(result);\n\n\t  return 1;\n}\n\n/*\n * Don't forget to lwfree() result !\n */\nBOX3D *\ncompute_serialized_box3d(uchar *srl)\n{\n\tint type = lwgeom_getType(srl[0]);\n\tint t;\n\tuchar *loc = srl;\n\tuint32 nelems;\n\tBOX3D *result;\n\tBOX3D b1;\n\tint sub_size;\n\tchar nboxes=0;\n\n\tLWDEBUGF(2, \"compute_serialized_box3d called on type %d\", type);\n\n\tloc += 1; /* Move past the 'type' byte. */\n\n\tif (lwgeom_hasBBOX(srl[0]))\n\t{\n\t\tloc += sizeof(BOX2DFLOAT4); /* Move past the bbox */\n\t}\n\n\tif (lwgeom_hasSRID(srl[0]) )\n\t{\n\t\tloc +=4; /* Move past the SRID */\n\t}\n\n\tif (type == POINTTYPE)\n\t{\n\t\tLWPOINT *pt = lwpoint_deserialize(srl);\n\n\t\tLWDEBUG(3, \"compute_serialized_box3d: lwpoint deserialized\");\n\n\t\tresult = lwpoint_compute_box3d(pt);\n\n\t\tLWDEBUG(3, \"compute_serialized_box3d: bbox found\");\n\n\t\tlwpoint_free(pt);\n\t\treturn result;\n\t}\n\n\t/* \n\t** For items that have elements (everything except points), \n\t** nelems == 0 => EMPTY geometry\n\t*/\n\tnelems = lw_get_uint32(loc);\n\tif ( nelems == 0 ) return NULL;\n\n \tif (type == LINETYPE)\n\t{\n\t\tLWLINE *line = lwline_deserialize(srl);\n\t\tresult = lwline_compute_box3d(line);\n\t\tlwline_free(line);\n\t\treturn result;\n\n\t}\n        else if (type == CIRCSTRINGTYPE)\n        {\n                LWCIRCSTRING *curve = lwcircstring_deserialize(srl);\n                result = lwcircstring_compute_box3d(curve);\n                lwcircstring_free(curve);\n                return result;\n        }\n\telse if (type == POLYGONTYPE)\n\t{\n\t\tLWPOLY *poly = lwpoly_deserialize(srl);\n\t\tresult = lwpoly_compute_box3d(poly);\n\t\tlwpoly_free(poly);\n\t\treturn result;\n\t}\n\n\tif ( ! ( type == MULTIPOINTTYPE || type == MULTILINETYPE ||\n\t\ttype == MULTIPOLYGONTYPE || type == COLLECTIONTYPE ||\n                type == COMPOUNDTYPE || type == CURVEPOLYTYPE ||\n                type == MULTICURVETYPE || type == MULTISURFACETYPE) )\n\t{\n\t\tlwnotice(\"compute_serialized_box3d called on unknown type %d\", type);\n\t\treturn NULL;\n\t}\n\n\tloc += 4;\n\n\t/* each sub-type */\n\tresult = NULL;\n\tfor (t=0; t<nelems; t++)\n\t{\n\t\tif ( compute_serialized_box3d_p(loc, &b1) ) \n\t\t{\n\t\t\tLWDEBUG(3, \"Geom %d have box:\"); \n#if POSTGIS_DEBUG_LEVEL >= 3\n\t\t\tprintBOX3D(&b1);\n#endif\n\n\t\t\tif (result)\n\t\t\t{\n\t\t\t\tnboxes += box3d_union_p(result, &b1, result);\n\t\t\t}\n\t\t\telse\n\t\t\t{ \n\t\t\t\tresult = lwalloc(sizeof(BOX3D));\n\t\t\t\tmemcpy(result, &b1, sizeof(BOX3D));\n\t\t\t}\n\t\t}\n\n\t\tsub_size = lwgeom_size(loc);\n\t\tloc += sub_size;\n\t}\n\n\treturn result;\n\n}\n\n/****************************************************************\n * memory management \n *\n *  these only delete the memory associated\n *  directly with the structure - NOT the stuff pointing into\n *  the original de-serialized info\n *\n ****************************************************************/\n\nvoid\nlwinspected_release(LWGEOM_INSPECTED *inspected)\n{\n\tif ( inspected->ngeometries )\n\t\tlwfree(inspected->sub_geoms);\n\tlwfree(inspected);\n}\n\n\n\n\n\n\n/************************************************\n * debugging routines\n ************************************************/\n\n\nvoid printBOX3D(BOX3D *box)\n{\n\tlwnotice(\"BOX3D: %g %g, %g %g\", box->xmin, box->ymin,\n\t\tbox->xmax, box->ymax);\n}\n\nvoid printPA(POINTARRAY *pa)\n{\n\tint t;\n\tPOINT4D pt;\n\tchar *mflag;\n\n\n\tif ( TYPE_HASM(pa->dims) ) mflag = \"M\";\n\telse mflag = \"\";\n\n\tlwnotice(\"      POINTARRAY%s{\", mflag);\n\tlwnotice(\"                 ndims=%i,   ptsize=%i\",\n\t\tTYPE_NDIMS(pa->dims), pointArray_ptsize(pa));\n\tlwnotice(\"                 npoints = %i\", pa->npoints);\n\n\tfor (t =0; t<pa->npoints;t++)\n\t{\n\t\tgetPoint4d_p(pa, t, &pt);\n\t\tif (TYPE_NDIMS(pa->dims) == 2)\n\t\t{\n\t\t\tlwnotice(\"                    %i : %lf,%lf\",t,pt.x,pt.y);\n\t\t}\n\t\tif (TYPE_NDIMS(pa->dims) == 3)\n\t\t{\n\t\t\tlwnotice(\"                    %i : %lf,%lf,%lf\",t,pt.x,pt.y,pt.z);\n\t\t}\n\t\tif (TYPE_NDIMS(pa->dims) == 4)\n\t\t{\n\t\t\tlwnotice(\"                    %i : %lf,%lf,%lf,%lf\",t,pt.x,pt.y,pt.z,pt.m);\n\t\t}\n\t}\n\n\tlwnotice(\"      }\");\n}\n\nvoid printBYTES(uchar *a, int n)\n{\n\tint t;\n\tchar buff[3];\n\n\tbuff[2] = 0; /* null terminate */\n\n\tlwnotice(\" BYTE ARRAY (n=%i) IN HEX: {\", n);\n\tfor (t=0;t<n;t++)\n\t{\n\t\tdeparse_hex(a[t], buff);\n\t\tlwnotice(\"    %i : %s\", t,buff );\n\t}\n\tlwnotice(\"  }\");\n}\n\n\nvoid\nprintMULTI(uchar *serialized)\n{\n\tLWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized);\n\tLWLINE  *line;\n\tLWPOINT *point;\n\tLWPOLY  *poly;\n\tint t;\n\n\tlwnotice(\"MULTI* geometry (type = %i), with %i sub-geoms\",lwgeom_getType((uchar)serialized[0]), inspected->ngeometries);\n\n\tfor (t=0;t<inspected->ngeometries;t++)\n\t{\n\t\tlwnotice(\"      sub-geometry %i:\", t);\n\t\tline = NULL; point = NULL; poly = NULL;\n\n\t\tline = lwgeom_getline_inspected(inspected,t);\n\t\tif (line !=NULL)\n\t\t{\n\t\t\tprintLWLINE(line);\n\t\t}\n\t\tpoly = lwgeom_getpoly_inspected(inspected,t);\n\t\tif (poly !=NULL)\n\t\t{\n\t\t\tprintLWPOLY(poly);\n\t\t}\n\t\tpoint = lwgeom_getpoint_inspected(inspected,t);\n\t\tif (point !=NULL)\n\t\t{\n\t\t\tprintPA(point->point);\n\t\t}\n    }\n\n    lwnotice(\"end multi*\");\n\n\tlwinspected_release(inspected);\n}\n\nvoid\nprintType(uchar type)\n{\n\tlwnotice(\"type 0x%x ==> hasBBOX=%i, hasSRID=%i, ndims=%i, type=%i\",(unsigned int) type, lwgeom_hasBBOX(type), lwgeom_hasSRID(type),lwgeom_ndims(type), lwgeom_getType(type));\n}\n\n/*\n * Get the SRID from the LWGEOM.\n * None present => -1\n */\nint\nlwgeom_getsrid(uchar *serialized)\n{\n\tuchar type = serialized[0];\n\tuchar *loc = serialized+1;\n\n\tif ( ! lwgeom_hasSRID(type)) return -1;\n\n\tif (lwgeom_hasBBOX(type))\n\t{\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t}\n\n\treturn lw_get_int32(loc);\n}\n\nchar\nptarray_isccw(const POINTARRAY *pa)\n{\n\tint i;\n\tdouble area = 0;\n\tPOINT2D p1, p2;\n\n\tfor (i=0; i<pa->npoints-1; i++)\n\t{\n\t\tgetPoint2d_p(pa, i, &p1);\n\t\tgetPoint2d_p(pa, i+1, &p2);\n\t\tarea += (p1.y * p2.x) - (p1.x * p2.y);\n\t}\n\tif ( area > 0 ) return 0;\n\telse return 1;\n}\n\n/*\n * Returns a BOX2DFLOAT4 that encloses b1 and b2\n *\n * box2d_union(NULL,A) --> A\n * box2d_union(A,NULL) --> A\n * box2d_union(A,B) --> A union B\n */\nBOX2DFLOAT4 *\nbox2d_union(BOX2DFLOAT4 *b1, BOX2DFLOAT4 *b2)\n{\n\tBOX2DFLOAT4 *result;\n\n\tif ( (b1 == NULL) && (b2 == NULL) )\n\t{\n\t\treturn NULL;\n\t}\n\n\tresult = lwalloc(sizeof(BOX2DFLOAT4));\n\n\tif  (b1 == NULL)\n\t{\n\t\tmemcpy(result, b2, sizeof(BOX2DFLOAT4));\n\t\treturn result;\n\t}\n\tif (b2 == NULL)\n\t{\n\t\tmemcpy(result, b1, sizeof(BOX2DFLOAT4));\n\t\treturn result;\n\t}\n\n\tif (b1->xmin < b2->xmin) result->xmin = b1->xmin;\n\telse result->xmin = b2->xmin;\n\n\tif (b1->ymin < b2->ymin) result->ymin = b1->ymin;\n\telse result->ymin = b2->ymin;\n\n\tif (b1->xmax > b2->xmax) result->xmax = b1->xmax;\n\telse result->xmax = b2->xmax;\n\n\tif (b1->ymax > b2->ymax) result->ymax = b1->ymax;\n\telse result->ymax = b2->ymax;\n\n\treturn result;\n}\n\n/*\n * ubox may be one of the two args...\n * return 1 if done something to ubox, 0 otherwise.\n */\nint\nbox2d_union_p(BOX2DFLOAT4 *b1, BOX2DFLOAT4 *b2, BOX2DFLOAT4 *ubox)\n{\n\tif ( (b1 == NULL) && (b2 == NULL) )\n\t{\n\t\treturn 0;\n\t}\n\n\tif  (b1 == NULL)\n\t{\n\t\tmemcpy(ubox, b2, sizeof(BOX2DFLOAT4));\n\t\treturn 1;\n\t}\n\tif (b2 == NULL)\n\t{\n\t\tmemcpy(ubox, b1, sizeof(BOX2DFLOAT4));\n\t\treturn 1;\n\t}\n\n\tif (b1->xmin < b2->xmin) ubox->xmin = b1->xmin;\n\telse ubox->xmin = b2->xmin;\n\n\tif (b1->ymin < b2->ymin) ubox->ymin = b1->ymin;\n\telse ubox->ymin = b2->ymin;\n\n\tif (b1->xmax > b2->xmax) ubox->xmax = b1->xmax;\n\telse ubox->xmax = b2->xmax;\n\n\tif (b1->ymax > b2->ymax) ubox->ymax = b1->ymax;\n\telse ubox->ymax = b2->ymax;\n\n\treturn 1;\n}\n\nconst char *\nlwgeom_typeflags(uchar type)\n{\n\tstatic char flags[5];\n\tint flagno=0;\n\tif ( TYPE_HASZ(type) ) flags[flagno++] = 'Z';\n\tif ( TYPE_HASM(type) ) flags[flagno++] = 'M';\n\tif ( TYPE_HASBBOX(type) ) flags[flagno++] = 'B';\n\tif ( TYPE_HASSRID(type) ) flags[flagno++] = 'S';\n\tflags[flagno] = '\\0';\n\n\tLWDEBUGF(4, \"Flags: %s - returning %p\", flags, flags);\n\n\treturn flags;\n}\n\n/*\n * Given a string with at least 2 chars in it, convert them to\n * a byte value.  No error checking done!\n */\nuchar\nparse_hex(char *str)\n{\n\t/* do this a little brute force to make it faster */\n\n\tuchar\t\tresult_high = 0;\n\tuchar\t\tresult_low = 0;\n\n\tswitch (str[0])\n\t{\n\t\tcase '0' :\n\t\t\tresult_high = 0;\n\t\t\tbreak;\n\t\tcase '1' :\n\t\t\tresult_high = 1;\n\t\t\tbreak;\n\t\tcase '2' :\n\t\t\tresult_high = 2;\n\t\t\tbreak;\n\t\tcase '3' :\n\t\t\tresult_high = 3;\n\t\t\tbreak;\n\t\tcase '4' :\n\t\t\tresult_high = 4;\n\t\t\tbreak;\n\t\tcase '5' :\n\t\t\tresult_high = 5;\n\t\t\tbreak;\n\t\tcase '6' :\n\t\t\tresult_high = 6;\n\t\t\tbreak;\n\t\tcase '7' :\n\t\t\tresult_high = 7;\n\t\t\tbreak;\n\t\tcase '8' :\n\t\t\tresult_high = 8;\n\t\t\tbreak;\n\t\tcase '9' :\n\t\t\tresult_high = 9;\n\t\t\tbreak;\n\t\tcase 'A' :\n\t\tcase 'a' :\n\t\t\tresult_high = 10;\n\t\t\tbreak;\n\t\tcase 'B' :\n\t\tcase 'b' :\n\t\t\tresult_high = 11;\n\t\t\tbreak;\n\t\tcase 'C' :\n\t\tcase 'c' :\n\t\t\tresult_high = 12;\n\t\t\tbreak;\n\t\tcase 'D' :\n\t\tcase 'd' :\n\t\t\tresult_high = 13;\n\t\t\tbreak;\n\t\tcase 'E' :\n\t\tcase 'e' :\n\t\t\tresult_high = 14;\n\t\t\tbreak;\n\t\tcase 'F' :\n\t\tcase 'f' :\n\t\t\tresult_high = 15;\n\t\t\tbreak;\n\t}\n\tswitch (str[1])\n\t{\n\t\tcase '0' :\n\t\t\tresult_low = 0;\n\t\t\tbreak;\n\t\tcase '1' :\n\t\t\tresult_low = 1;\n\t\t\tbreak;\n\t\tcase '2' :\n\t\t\tresult_low = 2;\n\t\t\tbreak;\n\t\tcase '3' :\n\t\t\tresult_low = 3;\n\t\t\tbreak;\n\t\tcase '4' :\n\t\t\tresult_low = 4;\n\t\t\tbreak;\n\t\tcase '5' :\n\t\t\tresult_low = 5;\n\t\t\tbreak;\n\t\tcase '6' :\n\t\t\tresult_low = 6;\n\t\t\tbreak;\n\t\tcase '7' :\n\t\t\tresult_low = 7;\n\t\t\tbreak;\n\t\tcase '8' :\n\t\t\tresult_low = 8;\n\t\t\tbreak;\n\t\tcase '9' :\n\t\t\tresult_low = 9;\n\t\t\tbreak;\n\t\tcase 'A' :\n\t\tcase 'a' :\n\t\t\tresult_low = 10;\n\t\t\tbreak;\n\t\tcase 'B' :\n\t\tcase 'b' :\n\t\t\tresult_low = 11;\n\t\t\tbreak;\n\t\tcase 'C' :\n\t\tcase 'c' :\n\t\t\tresult_low = 12;\n\t\t\tbreak;\n\t\tcase 'D' :\n\t\tcase 'd' :\n\t\t\tresult_low = 13;\n\t\t\tbreak;\n\t\tcase 'E' :\n\t\tcase 'e' :\n\t\t\tresult_low = 14;\n\t\t\tbreak;\n\t\tcase 'F' :\n\t\tcase 'f' :\n\t\t\tresult_low = 15;\n\t\t\tbreak;\n\t}\n\treturn (uchar) ((result_high<<4) + result_low);\n}\n\n\n/*\n * Given one byte, populate result with two byte representing\n * the hex number.\n *\n * Ie. deparse_hex( 255, mystr)\n *\t\t-> mystr[0] = 'F' and mystr[1] = 'F'\n *\n * No error checking done\n */\nvoid\ndeparse_hex(uchar str, char *result)\n{\n\tint\tinput_high;\n\tint  input_low;\n\tstatic char outchr[]={\"0123456789ABCDEF\" };\n\n\tinput_high = (str>>4);\n\tinput_low = (str & 0x0F);\n\n\tresult[0] = outchr[input_high];\n\tresult[1] = outchr[input_low];\n\n}\n\n\n/*\n * Find interpolation point I\n * between point A and point B \n * so that the len(AI) == len(AB)*F\n * and I falls on AB segment.\n *\n * Example:\n *\n *   F=0.5  :    A----I----B \n *   F=1    :    A---------B==I \n *   F=0    : A==I---------B\n *   F=.2   :    A-I-------B\n */\nvoid\ninterpolate_point4d(POINT4D *A, POINT4D *B, POINT4D *I, double F)\n{\n#if PARANOIA_LEVEL > 0\n\tdouble absF=fabs(F);\n\tif ( absF < 0 || absF > 1 )\n\t{\n\t\tlwerror(\"interpolate_point4d: invalid F (%g)\", F);\n\t}\n#endif\n\tI->x=A->x+((B->x-A->x)*F);\n\tI->y=A->y+((B->y-A->y)*F);\n\tI->z=A->z+((B->z-A->z)*F);\n\tI->m=A->m+((B->m-A->m)*F);\n}\n"
  },
  {
    "path": "src/liblwgeom/lwgparse.c",
    "content": "/*\n * Written by Ralph Mason ralph.mason<at>telogis.com\n *\n * Copyright Telogis 2004\n * www.telogis.com\n *\n */\n#include <string.h>\n#include <stdio.h>\n/* Solaris9 does not provide stdint.h */\n/* #include <stdint.h> */\n#include <inttypes.h>\n\n#include \"liblwgeom.h\"\n#include \"wktparse.h\"\n#include \"wktparse.tab.h\"\n\n/*\n * To get byte order\n#include <sys/types.h>\n#include <netinet/in.h>\n#include <netinet/in_systm.h>\n#include <netinet/ip.h>\n*/\n\nvoid set_zm(char z, char m);\nvoid close_parser(void);\n\ntypedef uint32_t int4;\n\ntypedef struct tag_tuple tuple;\n\nstruct tag_outputstate{\n\tuchar*\tpos;\n};\n\ntypedef struct tag_outputstate output_state;\ntypedef void (*output_func)(tuple* this, output_state* out);\ntypedef void (*read_col_func)(const char **f);\n\n\n\n/* Globals */\n\nint srid=-1;\n\nstatic int parser_ferror_occured;\nstatic allocator local_malloc;\nstatic report_error error_func;\n\nstruct tag_tuple{\n\toutput_func   of;\n\tunion union_tag {\n\t\tdouble points[4];\n\t\tint4   pointsi[4];\n\n\t\tstruct struct_tag {\n\t\t\ttuple* \tstack_next;\n\t\t\tint\ttype;\n\t\t\tint\tnum;\n\t\t\tint\tsize_here;\n\t\t} nn;\n\t} uu;\n\tstruct tag_tuple *next;\n};\n\nstruct {\n\tint\ttype;\n\tint\tflags;\n\tint\tsrid;\n\tint\tndims;\n\tint\thasZ;\n\tint\thasM;\n\t/* create integer version */\n\tint lwgi;\n\t/* input is integer (wkb only)*/\n\tint from_lwgi;\n\n\tint4 alloc_size;\n\n\t/*\n\t\tlinked list of all tuples\n\t*/\n\ttuple*\tfirst;\n\ttuple*  last;\n\n\t/*\n\t\tstack of open geometries\n\t*/\n\ttuple*  stack;\n\n} the_geom;\n\ntuple* free_list=0;\n\n\n/*\n * Parser current instance check flags - a bitmap of flags that determine which checks are enabled during the current parse \n * (see liblwgeom.h for the related PARSER_CHECK constants)\n */\nint current_parser_check_flags;\n\n/*\n * Parser current instance result structure - the result structure being used for the current parse\n */\nLWGEOM_PARSER_RESULT *current_lwg_parser_result;\n\n\n/* Parser state flags - these are set automatically by the parser */\nint minpoints;\nint checkclosed;\n\n/*\n * This indicates if the number of points in the geometry is required to\n * be odd (one) or even (zero, currently not enforced) or whatever (-one)\n */\nint isodd;\ndouble *first_point=NULL;\ndouble *last_point=NULL;\n\n\n/*\n * Parser error messages\n *\n * IMPORTANT: Make sure the order of these messages matches the PARSER_ERROR constants in liblwgeom.h!\n * The 0th element should always be empty since it is unused (error constants start from -1)\n */\n\nconst char *parser_error_messages[] = {\n\t\"\",\n\t\"geometry requires more points\",\n\t\"geometry must have an odd number of points\",\n\t\"geometry contains non-closed rings\",\n\t\"can not mix dimensionality in a geometry\",\n\t\"parse error - invalid geometry\",\n\t\"invalid WKB type\"\n};\n\n/* Macro to return the error message and the current position within WKT */ \n#define LWGEOM_WKT_PARSER_ERROR(errcode) \\\n\tdo { \\\n\t\tif (!parser_ferror_occured) { \\\n\t\t\tparser_ferror_occured = -1 * errcode; \\\n\t\t\tcurrent_lwg_parser_result->message = parser_error_messages[errcode]; \\\n\t\t\tcurrent_lwg_parser_result->errlocation = lwg_parse_yylloc.last_column; \\\n\t\t} \\\n\t} while (0);\n\n\n/* Macro to return the error message and the current position within WKB \n   NOTE: the position is handled automatically by strhex_readbyte */ \n#define LWGEOM_WKB_PARSER_ERROR(errcode) \\\n\tdo { \\\n\t\tif (!parser_ferror_occured) { \\\n\t\t\tparser_ferror_occured = -1 * errcode; \\\n\t\t\tcurrent_lwg_parser_result->message = parser_error_messages[errcode]; \\\n\t\t} \\\n\t} while (0);\n\n\n/* External functions */\nextern void init_parser(const char *);\n\n/* Prototypes */\ntuple* alloc_tuple(output_func of,size_t size);\nvoid free_tuple(tuple* to_free);\nvoid inc_num(void);\nvoid alloc_stack_tuple(int type,output_func of,size_t size);\nvoid check_dims(int num);\nvoid WRITE_DOUBLES(output_state* out,double* points, int cnt);\n#ifdef SHRINK_INTS\nvoid WRITE_INT4(output_state * out,int4 val);\n#endif\nvoid empty_stack(tuple* this,output_state* out);\nvoid alloc_lwgeom(int srid);\nvoid write_point_2(tuple* this,output_state* out);\nvoid write_point_3(tuple* this,output_state* out);\nvoid write_point_4(tuple* this,output_state* out);\nvoid write_point_2i(tuple* this,output_state* out);\nvoid write_point_3i(tuple* this,output_state* out);\nvoid write_point_4i(tuple* this,output_state* out);\nvoid alloc_point_2d(double x,double y);\nvoid alloc_point_3d(double x,double y,double z);\nvoid alloc_point_4d(double x,double y,double z,double m);\nvoid write_type(tuple* this,output_state* out);\nvoid write_count(tuple* this,output_state* out);\nvoid write_type_count(tuple* this,output_state* out);\nvoid alloc_point(void);\nvoid alloc_linestring(void);\nvoid alloc_linestring_closed(void);\nvoid alloc_circularstring(void);\nvoid alloc_circularstring_closed(void);\nvoid alloc_polygon(void);\nvoid alloc_multipoint(void);\nvoid alloc_multilinestring(void);\nvoid alloc_multicurve(void);\nvoid alloc_multipolygon(void);\nvoid alloc_multisurface(void);\nvoid alloc_geomertycollection(void);\nvoid alloc_counter(void);\nvoid alloc_empty(void);\nvoid make_serialized_lwgeom(LWGEOM_PARSER_RESULT *lwg_parser_result);\nuchar strhex_readbyte(const char *in);\nuchar read_wkb_byte(const char **in);\nvoid read_wkb_bytes(const char **in, uchar* out, int cnt);\nint4 read_wkb_int(const char **in);\ndouble read_wkb_double(const char **in, int convert_from_int);\nvoid read_wkb_point(const char **b);\nvoid read_wkb_polygon(const char **b);\nvoid read_wkb_linestring(const char **b);\nvoid read_wkb_circstring(const char **b);\nvoid read_wkb_ordinate_array(const char **b);\nvoid read_collection(const char **b, read_col_func f);\nvoid parse_wkb(const char **b);\nvoid alloc_wkb(const char *parser);\nint parse_it(LWGEOM_PARSER_RESULT *lwg_parser_result, const char* geometry, int flags, allocator allocfunc, report_error errfunc);\nint parse_lwg(LWGEOM_PARSER_RESULT *lwg_parser_result, const char* geometry, int flags, allocator allocfunc, report_error errfunc);\nint parse_lwgi(LWGEOM_PARSER_RESULT *lwg_parser_result, const char* geometry, int flags, allocator allocfunc, report_error errfunc);\n\nvoid\nset_srid(double d_srid)\n{\n\tif ( d_srid >= 0 )\n\t\td_srid+=0.1;\n\telse\n\t\td_srid-=0.1;\n\n\n\tsrid=(int)(d_srid+0.1);\n}\n\ntuple *\nalloc_tuple(output_func of,size_t size)\n{\n\ttuple* ret = free_list;\n\n\tif ( ! ret ){\n\t\tint toalloc = (ALLOC_CHUNKS /sizeof(tuple));\n\t\tret = malloc( toalloc *sizeof(tuple) );\n\n\t\tfree_list = ret;\n\n\t\twhile(--toalloc){\n\t\t\tret->next = ret+1;\n\t\t\tret++;\n\t\t}\n\n\t\tret->next = NULL;\n\n\t\treturn alloc_tuple(of,size);\n\t}\n\n\tfree_list = ret->next;\n\tret->of = of;\n\tret->next = NULL;\n\n\tif ( the_geom.last ) {\n\t\tthe_geom.last->next = ret;\n\t\tthe_geom.last = ret;\n\t}\n\telse {\n\t\tthe_geom.first = the_geom.last = ret;\n\t}\n\n\tthe_geom.alloc_size += size;\n\treturn ret;\n}\n\nvoid\nfree_tuple(tuple* to_free)\n{\n\n\ttuple* list_end = to_free;\n\n\tif( !to_free)\n\t\treturn;\n\n\twhile(list_end->next){\n\t\tlist_end=list_end->next;\n\t}\n\n\tlist_end->next = free_list;\n\tfree_list = to_free;\n}\n\nvoid\ninc_num(void)\n{\n\tthe_geom.stack->uu.nn.num++;\n}\n\n/*\n\tAllocate a 'counting' tuple\n*/\nvoid\nalloc_stack_tuple(int type,output_func of,size_t size)\n{\n\ttuple*\tp;\n\tinc_num();\n\n        LWDEBUGF(2, \"alloc_stack_tuple %d, %d\", type, size);\n\t\n\tp = alloc_tuple(of,size);\n\tp->uu.nn.stack_next = the_geom.stack;\n\tp->uu.nn.type = type;\n\tp->uu.nn.size_here = the_geom.alloc_size;\n\tp->uu.nn.num = 0;\n\tthe_geom.stack = p;\n}\n\nvoid\npop(void)\n{\n\tthe_geom.stack = the_geom.stack->uu.nn.stack_next;\n}\n\nvoid\npopc(void)\n{\n\t/* If the minimum point check has been enabled, perform it */\n\tif (current_parser_check_flags & PARSER_CHECK_MINPOINTS) {\n\t\tif ( the_geom.stack->uu.nn.num < minpoints){\n\t\t\tLWGEOM_WKT_PARSER_ERROR(PARSER_ERROR_MOREPOINTS);\n\t\t}\n\t}\n\n\t/* If the odd number point check has been enabled, perform it */\n\tif (current_parser_check_flags & PARSER_CHECK_ODD) {\n        \tif(isodd != -1 && the_geom.stack->uu.nn.num % 2 != isodd) {\n                \tLWGEOM_WKT_PARSER_ERROR(PARSER_ERROR_ODDPOINTS);\n        \t}\n\t}\n\n\t/* If the polygon closure check has been enabled, perform it */\n\tif (current_parser_check_flags & PARSER_CHECK_CLOSURE) {\n\t\tif ( checkclosed && first_point && last_point) {\n\t\t\tif ( memcmp(first_point, last_point,\n\t\t\t\tsizeof(double)*the_geom.ndims) )\n\t\t\t{\n\t\t\t\tLWGEOM_WKT_PARSER_ERROR(PARSER_ERROR_UNCLOSED);\n\t\t\t}\n\t\t}\t\n\t}\n\n\tthe_geom.stack = the_geom.stack->uu.nn.stack_next;\n}\n\n\nvoid\ncheck_dims(int num)\n{\n        LWDEBUGF(2, \"check_dims the_geom.ndims = %d, num = %d\", the_geom.ndims, num);\n\n\tif( the_geom.ndims != num){\n\t\tif (the_geom.ndims) {\n\t\t\tLWGEOM_WKT_PARSER_ERROR(PARSER_ERROR_MIXDIMS);\n\t\t} else {\n\n                        LWDEBUGF(3, \"check_dims: setting dim %d\", num);\n\n\t\t\tthe_geom.ndims = num;\n\t\t\tif ( num > 2 ) the_geom.hasZ = 1;\n\t\t\tif ( num > 3 ) the_geom.hasM = 1;\n\t\t}\n\t}\n}\n\n#define WRITE_INT4_REAL(x,y) { memcpy(x->pos,&y,4); x->pos+=4;}\n#define WRITE_INT4_REAL_MULTIPLE(x,y,z) { memcpy(x->pos,&y,z*4); x->pos+=(z*4);}\n\n/*\n\twe can shrink ints to one byte if they are less than 127\n\tby setting the extra bit.  Because if the different byte\n\tordering possibilities we need to set the lsb on little\n\tendian to show a packed one and the msb on a big endian\n\tmachine\n*/\n#ifdef SHRINK_INTS\nvoid\nWRITE_INT4(output_state * out,int4 val)\n{\n\tif ( val <= 0x7f ){\n\t\tif ( getMachineEndian() == NDR ){\n\t\t\tval = (val<<1) | 1;\n\t\t}\n\t\telse{\n\t\t\tval |=0x80;\n\t\t}\n\n\t\t*out->pos++ = (uchar)val;\n\t\tthe_geom.alloc_size-=3;\n\t}\n\telse{\n\t\tif ( getMachineEndian() == NDR ){\n\t\t\tval <<=1;\n\t\t}\n\t\tWRITE_INT4_REAL(out,val);\n\t}\n}\n#else\n#define WRITE_INT4 WRITE_INT4_REAL\n#endif\n\n\nvoid\nWRITE_DOUBLES(output_state* out,double* points, int cnt)\n{\n\tif ( the_geom.lwgi){\n\t\tint4 vals[4];\n\t\tint i;\n\n\t\tfor(i=0; i<cnt;i++){\n\t\t\tvals[i] = (int4)(((points[i]+180.0)*0xB60B60)+.5);\n\t\t}\n\t\tmemcpy(out->pos,vals,sizeof(int4)*cnt);\n\t\tout->pos+=sizeof(int4)*cnt;\n\t}\n\telse{\n\t\tmemcpy(out->pos,points,sizeof(double)*cnt);\n\t\tout->pos+=sizeof(double)*cnt;\n\t}\n\n}\n\nvoid\nempty_stack(tuple *this,output_state* out)\n{\n    /* Do nothing but provide an empty base for the geometry stack */\n}\n\nvoid\nalloc_lwgeom(int srid)\n{\n        LWDEBUGF(2, \"alloc_lwgeom %d\", srid);\n\n\tthe_geom.srid=srid;\n\tthe_geom.alloc_size=0;\n\tthe_geom.stack=NULL;\n\tthe_geom.ndims=0;\n\tthe_geom.hasZ=0;\n\tthe_geom.hasM=0;\n\n\t/* Free if used already */\n\tif ( the_geom.first ){\n\t\tfree_tuple(the_geom.first);\n\t\tthe_geom.first=the_geom.last=NULL;\n\t}\n\n\tif ( srid != -1 ){\n\t\tthe_geom.alloc_size+=4;\n\t}\n\n    /* Setup up an empty tuple as the stack base */\n    the_geom.stack = alloc_tuple(empty_stack, 0);\n}\n\nvoid\nwrite_point_2(tuple* this,output_state* out)\n{\n\tWRITE_DOUBLES(out,this->uu.points,2);\n}\n\nvoid\nwrite_point_3(tuple* this,output_state* out)\n{\n\tWRITE_DOUBLES(out,this->uu.points,3);\n}\n\nvoid\nwrite_point_4(tuple* this,output_state* out)\n{\n\tWRITE_DOUBLES(out,this->uu.points,4);\n}\n\nvoid\nwrite_point_2i(tuple* this,output_state* out)\n{\n\tWRITE_INT4_REAL_MULTIPLE(out,this->uu.points,2);\n}\n\nvoid\nwrite_point_3i(tuple* this,output_state* out)\n{\n\tWRITE_INT4_REAL_MULTIPLE(out,this->uu.points,3);\n}\n\nvoid\nwrite_point_4i(tuple* this,output_state* out)\n{\n\tWRITE_INT4_REAL_MULTIPLE(out,this->uu.points,4);\n}\n\nvoid\nalloc_point_2d(double x,double y)\n{\n\ttuple* p = alloc_tuple(write_point_2,the_geom.lwgi?8:16);\n\tp->uu.points[0] = x;\n\tp->uu.points[1] = y;\n\n        LWDEBUGF(2, \"alloc_point_2d %f,%f\", x, y);\n\t\n\t/* keep track of point */\n\tif ( checkclosed ) {\n\t\tif ( ! the_geom.stack->uu.nn.num )\n\t\t\tfirst_point = p->uu.points;\n\t\tlast_point = p->uu.points;\n\t}\n\n\tinc_num();\n\tcheck_dims(2);\n}\n\nvoid\nalloc_point_3d(double x,double y,double z)\n{\n\ttuple* p = alloc_tuple(write_point_3,the_geom.lwgi?12:24);\n\tp->uu.points[0] = x;\n\tp->uu.points[1] = y;\n\tp->uu.points[2] = z;\n\n        LWDEBUGF(2, \"alloc_point_3d %f, %f, %f\", x, y, z);\n\t\n\t/* keep track of point */\n\tif ( checkclosed ) {\n\t\tif ( ! the_geom.stack->uu.nn.num )\n\t\t\tfirst_point = p->uu.points;\n\t\tlast_point = p->uu.points;\n\t}\n\n\tinc_num();\n\tcheck_dims(3);\n}\n\nvoid\nalloc_point_4d(double x,double y,double z,double m)\n{\n\ttuple* p = alloc_tuple(write_point_4,the_geom.lwgi?16:32);\n\tp->uu.points[0] = x;\n\tp->uu.points[1] = y;\n\tp->uu.points[2] = z;\n\tp->uu.points[3] = m;\n\n        LWDEBUGF(2, \"alloc_point_4d %f, %f, %f, %f\", x, y, z, m);\n\n\t/* keep track of point */\n\tif ( checkclosed ) {\n\t\tif ( ! the_geom.stack->uu.nn.num )\n\t\t\tfirst_point = p->uu.points;\n\t\tlast_point = p->uu.points;\n\t}\n\n\tinc_num();\n\tcheck_dims(4);\n}\n\nvoid\nwrite_type(tuple* this,output_state* out)\n{\n\tuchar type=0;\n\n\t/* Empty handler - switch back */\n\tif ( this->uu.nn.type == 0xff )\n\t\tthis->uu.nn.type = COLLECTIONTYPE;\n\n\ttype |= this->uu.nn.type;\n\n\tif (the_geom.ndims) /* Support empty */\n\t{\n\t\tTYPE_SETZM(type, the_geom.hasZ, the_geom.hasM);\n\t}\n\n\tif ( the_geom.srid != -1 ){\n\t\ttype |= 0x40;\n\t}\n\n\t*(out->pos)=type;\n\tout->pos++;\n\n\tif ( the_geom.srid != -1 ){\n\t\t/* Only the first geometry will have a srid attached */\n\t\tWRITE_INT4(out,the_geom.srid);\n\t\tthe_geom.srid = -1;\n\t}\n}\n\nvoid\nwrite_count(tuple* this,output_state* out)\n{\n\tint num = this->uu.nn.num;\n\tWRITE_INT4(out,num);\n}\n\nvoid\nwrite_type_count(tuple* this,output_state* out)\n{\n\twrite_type(this,out);\n\twrite_count(this,out);\n}\n\nvoid\nalloc_point(void)\n{\n        LWDEBUG(2, \"alloc_point\");\n\n\tif( the_geom.lwgi)\n\t\talloc_stack_tuple(POINTTYPEI,write_type,1);\n\telse\n\t\talloc_stack_tuple(POINTTYPE,write_type,1);\n\n\tminpoints=1;\n\tcheckclosed=0;\n        isodd=-1;\n}\n\nvoid\nalloc_linestring(void)\n{\n        LWDEBUG(2, \"alloc_linestring\");\n\n\tif( the_geom.lwgi)\n\t\talloc_stack_tuple(LINETYPEI,write_type,1);\n\telse\n\t\talloc_stack_tuple(LINETYPE,write_type,1);\n\n\tminpoints=2;\n\tcheckclosed=0;\n        isodd=-1;\n}\n\nvoid alloc_linestring_closed(void)\n{\n        LWDEBUG(2, \"alloc_linestring_closed called.\");\n\n        alloc_linestring();\n        checkclosed=1;\n}\n\nvoid\nalloc_circularstring(void)\n{\n        LWDEBUG(2, \"alloc_circularstring\");\n\n        alloc_stack_tuple(CIRCSTRINGTYPE,write_type,1);\n        minpoints=3;\n        checkclosed=0;\n        isodd=1;\n}\n\nvoid alloc_circularstring_closed(void)\n{\n        LWDEBUG(2, \"alloc_circularstring_closed\");\n\n        alloc_circularstring();\n        checkclosed=1;\n}\n\nvoid\nalloc_polygon(void)\n{\n        LWDEBUG(2, \"alloc_polygon\");\n\n\tif( the_geom.lwgi)\n\t\talloc_stack_tuple(POLYGONTYPEI, write_type,1);\n\telse\n\t\talloc_stack_tuple(POLYGONTYPE, write_type,1);\n\n\tminpoints=4;\n\tcheckclosed=1;\n        isodd=-1;\n\n}\n\nvoid\nalloc_curvepolygon(void)\n{\n        LWDEBUG(2, \"alloc_curvepolygon called.\");\n\n        alloc_stack_tuple(CURVEPOLYTYPE, write_type, 1);\n        minpoints=4;\n        checkclosed=1;\n        isodd=-1;\n}\n\nvoid\nalloc_compoundcurve(void)\n{\n        LWDEBUG(2, \"alloc_compoundcurve called.\");\n\n        alloc_stack_tuple(COMPOUNDTYPE, write_type, 1);\n}\n\nvoid\nalloc_multipoint(void)\n{\n        LWDEBUG(2, \"alloc_multipoint\");\n\n\talloc_stack_tuple(MULTIPOINTTYPE,write_type,1);\n}\n\nvoid\nalloc_multilinestring(void)\n{\n        LWDEBUG(2, \"alloc_multilinestring\");\n\n\talloc_stack_tuple(MULTILINETYPE,write_type,1);\n}\n\nvoid\nalloc_multicurve(void)\n{\n        LWDEBUG(2, \"alloc_multicurve\");\n\n        alloc_stack_tuple(MULTICURVETYPE,write_type,1);\n}\n\nvoid\nalloc_multipolygon(void)\n{\n        LWDEBUG(2, \"alloc_multipolygon\");\n\n\talloc_stack_tuple(MULTIPOLYGONTYPE,write_type,1);\n}\n\nvoid\nalloc_multisurface(void)\n{\n        LWDEBUG(2, \"alloc_multisurface called\");\n\n        alloc_stack_tuple(MULTISURFACETYPE,write_type,1);\n}\n\nvoid\nalloc_geomertycollection(void)\n{\n        LWDEBUG(2, \"alloc_geometrycollection\");\n\n\talloc_stack_tuple(COLLECTIONTYPE,write_type,1);\n}\n\nvoid\nalloc_counter(void)\n{\n        LWDEBUG(2, \"alloc_counter\");\n\n\talloc_stack_tuple(0,write_count,4);\n}\n\nvoid\nalloc_empty(void)\n{\n\ttuple* st = the_geom.stack;\n\n\tLWDEBUG(2, \"alloc_empty\");\n\n\t/* Find the last geometry */\n\twhile(st->uu.nn.type == 0){\n\t\tst =st->uu.nn.stack_next;\n\t}\n\n\t/* Reclaim memory */\n\tfree_tuple(st->next);\n\n\t/* Put an empty geometry collection on the top of the stack */\n\tst->next=NULL;\n\tthe_geom.stack=st;\n\tthe_geom.alloc_size=st->uu.nn.size_here;\n\n\t/* Mark as a empty stop */\n\tif (st->uu.nn.type != 0xFF){\n\t\tst->uu.nn.type=0xFF;\n\t\tst->of = write_type_count;\n\t\tthe_geom.alloc_size+=4;\n\t\tst->uu.nn.size_here=the_geom.alloc_size;\n\t}\n\n\tst->uu.nn.num=0;\n}\n\nvoid\nmake_serialized_lwgeom(LWGEOM_PARSER_RESULT *lwg_parser_result)\n{\n\tuchar* out_c;\n\toutput_state out;\n\ttuple* cur;\n\t\n\tLWDEBUG(2, \"make_serialized_lwgeom\");\n\n\t/* Allocate the LWGEOM itself */\n\tout_c = (uchar*)local_malloc(the_geom.alloc_size);\n\tout.pos = out_c;\n\tcur = the_geom.first ;\n\n\twhile(cur){\n\t\tcur->of(cur,&out);\n\t\tcur=cur->next;\n\t}\n\n\t/* Setup the LWGEOM_PARSER_RESULT structure */\n\tlwg_parser_result->serialized_lwgeom = out_c;\n\tlwg_parser_result->size = the_geom.alloc_size;\n\n\treturn;\n}\n\nvoid\nlwg_parse_yynotice(char* s)\n{\n        lwnotice(s);\n}\n\nint\nlwg_parse_yyerror(char* s)\n{\n\tLWGEOM_WKT_PARSER_ERROR(PARSER_ERROR_INVALIDGEOM);\n\treturn 1;\n}\n\n/*\n Table below generated using this ruby.\n\n a=(0..0xff).to_a.collect{|x|0xff};('0'..'9').each{|x|a[x[0]]=x[0]-'0'[0]}\n ('a'..'f').each{|x|v=x[0]-'a'[0]+10;a[x[0]]=a[x.upcase[0]]=v}\n puts '{'+a.join(\",\")+'}'\n\n */\nstatic const uchar to_hex[]  = {\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t0,1,2,3,4,5,6,7,8,9,255,255,255,255,255,255,255,10,11,12,13,14,\n\t15,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255,255,255,255,10,11,12,13,14,15,255,\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n\t255,255,255,255,255,255,255,255};\n\nuchar\nstrhex_readbyte(const char* in)\n{\n\tif ( *in == 0 ){\n\t\tif ( ! parser_ferror_occured){\n\t\t\tLWGEOM_WKB_PARSER_ERROR(PARSER_ERROR_INVALIDGEOM);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tif (!parser_ferror_occured) {\n\t\tlwg_parse_yylloc.last_column++;\n\t\treturn to_hex[(int)*in]<<4 | to_hex[(int)*(in+1)];\n\t} else {\n\t\treturn 0;\n\t}\n}\n\nuchar\nread_wkb_byte(const char** in)\n{\n\tuchar ret = strhex_readbyte(*in);\n\t(*in)+=2;\n\treturn ret;\n}\n\nint swap_order;\n\nvoid\nread_wkb_bytes(const char** in, uchar* out, int cnt)\n{\n\tif ( ! swap_order ){\n\t\twhile(cnt--) *out++ = read_wkb_byte(in);\n\t}\n\telse{\n\t\tout += (cnt-1);\n\t\twhile(cnt--) *out-- = read_wkb_byte(in);\n\t}\n}\n\nint4\nread_wkb_int(const char** in)\n{\n\tint4 ret=0;\n\tread_wkb_bytes(in,(uchar*)&ret,4);\n\treturn ret;\n}\n\ndouble\nread_wkb_double(const char** in, int convert_from_int)\n{\n\tdouble ret=0;\n\n\tif ( ! convert_from_int){\n\t\tread_wkb_bytes(in,(uchar*)&ret,8);\n\t\treturn ret;\n\t}else{\n\t\tret  = read_wkb_int(in);\n\t\tret /= 0xb60b60;\n\t\treturn ret-180.0;\n \t}\n}\n\nvoid\nread_wkb_point(const char **b)\n{\n\tint i;\n\ttuple* p = NULL;\n\n\n\tif(the_geom.lwgi && the_geom.from_lwgi ){\n\t\t/*\n\t\t * Special case - reading from lwgi to lwgi\n\t\t * we don't want to go via doubles in the middle.\n\t\t */\n\t\tswitch(the_geom.ndims){\n\t\t\tcase 2: p=alloc_tuple(write_point_2i,8); break;\n\t\t\tcase 3: p=alloc_tuple(write_point_3i,12); break;\n\t\t\tcase 4: p=alloc_tuple(write_point_4i,16); break;\n\t\t}\n\n\t\tfor(i=0;i<the_geom.ndims;i++){\n\t\t\tp->uu.pointsi[i]=read_wkb_int(b);\n\t\t}\n\t}\n\telse{\n\t\tint mul = the_geom.lwgi ? 1 : 2;\n\n\t\tswitch(the_geom.ndims){\n\t\t\tcase 2: p=alloc_tuple(write_point_2,8*mul); break;\n\t\t\tcase 3: p=alloc_tuple(write_point_3,12*mul); break;\n\t\t\tcase 4: p=alloc_tuple(write_point_4,16*mul); break;\n\t\t}\n\n\t\tfor(i=0;i<the_geom.ndims;i++){\n\t\t\tp->uu.points[i]=read_wkb_double(b,the_geom.from_lwgi);\n\t\t}\n\t}\n\n\n\t/* keep track of point */\n\tif ( checkclosed ) {\n\t\tif ( ! the_geom.stack->uu.nn.num )\n\t\t\tfirst_point = p->uu.points;\n\t\tlast_point = p->uu.points;\n\t}\n\n\tinc_num();\n\tcheck_dims(the_geom.ndims);\n}\n\nvoid\nread_wkb_polygon(const char **b)\n{\n\t/* Stack the number of ORDINATE_ARRAYs (rings) */\n\tint4 cnt=read_wkb_int(b);\n\talloc_counter();\n\n\t/* Read through each ORDINATE_ARRAY in turn */\n\twhile(cnt--){\n\t\tif ( parser_ferror_occured )\treturn;\n\n\t\t/* Things to check for POLYGON ORDINATE_ARRAYs */\n\t\tminpoints=4;\n\t\tcheckclosed=1;\n\t\tisodd=-1;\n\n\t\tread_wkb_ordinate_array(b);\n\t}\n\n\tpop();\n}\n\nvoid\nread_wkb_linestring(const char **b)\n{\n\n\t/* Things to check for LINESTRING ORDINATE_ARRAYs */\n\tminpoints=2;\n\tcheckclosed=0;\n\tisodd=-1;\n\n\tread_wkb_ordinate_array(b);\n}\n\n\nvoid\nread_wkb_circstring(const char **b)\n{\n\n\t/* Things to check for CIRCULARSTRING ORDINATE_ARRAYs */\n\tminpoints=3;\n\tcheckclosed=0;\n\tisodd=-1;\n\n\tread_wkb_ordinate_array(b);\n}\n\nvoid\nread_wkb_ordinate_array(const char **b)\n{\n\t/* Read through a WKB ordinate array */\n\tint4 cnt=read_wkb_int(b);\n\talloc_counter();\n\n\twhile(cnt--){\n\t\tif ( parser_ferror_occured )\treturn;\n\t\tread_wkb_point(b);\n\t}\n\n\t/* Perform a check of the ordinate array */\n\tpopc();\n}\n\nvoid\nread_collection(const char **b, read_col_func f)\n{\n\t/* Read through a COLLECTION or an EWKB */\n\tint4 cnt=read_wkb_int(b);\n\talloc_counter();\n\n\twhile(cnt--){\n\t\tif ( parser_ferror_occured )\treturn;\n\t\tf(b);\n\t}\n\n\tpop();\n}\n\nvoid\nparse_wkb(const char **b)\n{\n\tint4 type;\n\tuchar xdr = read_wkb_byte(b);\n\tint4 localsrid;\n\n        LWDEBUG(2, \"parse_wkb\");\n\n\tswap_order=0;\n\n\tif ( xdr != getMachineEndian() )\n\t{\n\t\tswap_order=1;\n\t}\n\n\ttype = read_wkb_int(b);\n\n\t/* quick exit on error */\n\tif ( parser_ferror_occured ) return;\n\n\tthe_geom.ndims=2;\n\tif (type & WKBZOFFSET)\n\t{\n\t\tthe_geom.hasZ = 1;\n\t\tthe_geom.ndims++;\n\t}\n\telse the_geom.hasZ = 0;\n\tif (type & WKBMOFFSET)\n\t{\n\t\tthe_geom.hasM = 1;\n\t\tthe_geom.ndims++;\n\t}\n\telse the_geom.hasM = 0;\n\n\tif (type & WKBSRIDFLAG )\n\t{\n\t\t/* local (in-EWKB) srid spec overrides SRID=#; */\n\t\tlocalsrid = read_wkb_int(b);\n\t\tif ( localsrid != -1 )\n\t\t{\n\t\t\tif ( the_geom.srid == -1 ) the_geom.alloc_size += 4;\n\t\t\tthe_geom.srid = localsrid;\n\t\t}\n\t}\n\n\ttype &=0x0f;\n\n\tif ( the_geom.lwgi  ){\n\n\t\tif ( type<= POLYGONTYPE )\n\t\t\talloc_stack_tuple(type +9,write_type,1);\n\t\telse\n\t\t\talloc_stack_tuple(type,write_type,1);\n\t}\n\telse{\n\t\t/* If we are writing lwg and are reading wbki */\n\t\tint4 towrite=type;\n\t\tif (towrite >= POINTTYPEI && towrite <= POLYGONTYPEI){\n\t\t\ttowrite-=9;\n\t\t}\n\t\talloc_stack_tuple(towrite,write_type,1);\n\t}\n\n\tswitch(type ){\n\t\tcase\tPOINTTYPE:\n\t\t\tread_wkb_point(b);\n\t\t\tbreak;\n\n\t\tcase\tLINETYPE:\n\t\t\tread_wkb_linestring(b);\n\t\t\tbreak;\n\n                case    CIRCSTRINGTYPE:\n                        read_wkb_circstring(b);\n                        break;\n\n\t\tcase\tPOLYGONTYPE:\n\t\t\tread_wkb_polygon(b);\n\t\t\tbreak;\n\n                case    COMPOUNDTYPE:\n                        read_collection(b,parse_wkb);\n                        break;\n\n                case    CURVEPOLYTYPE:\n                        read_collection(b,parse_wkb);\n                        break;\n\n\t\tcase\tMULTIPOINTTYPE:\n\t\tcase\tMULTILINETYPE:\n                case    MULTICURVETYPE:\n\t\tcase\tMULTIPOLYGONTYPE:\n                case    MULTISURFACETYPE:\n\t\tcase\tCOLLECTIONTYPE:\n\t\t\tread_collection(b,parse_wkb);\n\t\t\tbreak;\n\n\t\tcase\tPOINTTYPEI:\n\t\t\tthe_geom.from_lwgi=1;\n\t\t\tread_wkb_point(b);\n\t\t\tbreak;\n\n\t\tcase\tLINETYPEI:\n\t\t\tthe_geom.from_lwgi=1;\n\t\t\tread_wkb_linestring(b);\n\t\t\tbreak;\n\n\t\tcase\tPOLYGONTYPEI:\n\t\t\tthe_geom.from_lwgi=1;\n\t\t\tread_wkb_polygon(b);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tLWGEOM_WKB_PARSER_ERROR(PARSER_ERROR_INVALIDWKBTYPE);\n\t}\n\n\tthe_geom.from_lwgi=0;\n\n\tpop();\n}\n\n\nvoid\nalloc_wkb(const char *parser)\n{\n        LWDEBUG(2, \"alloc_wkb\");\n\n\tparse_wkb(&parser);\n}\n\n/*\n\tParse a string and return a LW_GEOM\n*/\nint\nparse_it(LWGEOM_PARSER_RESULT *lwg_parser_result, const char *geometry, int flags, allocator allocfunc, report_error errfunc)\n{\n        LWDEBUGF(2, \"parse_it: %s with parser flags %d\", geometry, flags);\n\n\tlocal_malloc = allocfunc;\n\terror_func=errfunc;\n\n\tparser_ferror_occured = 0;\n\n\t/* Setup the inital parser flags and empty the return struct */\n\tcurrent_lwg_parser_result = lwg_parser_result;\n\tcurrent_parser_check_flags = flags;\n\tlwg_parser_result->serialized_lwgeom = NULL;\n\tlwg_parser_result->size = 0;\n\tlwg_parser_result->wkinput = geometry;\n\n\tinit_parser(geometry);\n\n\tlwg_parse_yyparse();\n\n\tclose_parser();\n\n\t/* Return the parsed geometry */\n\tmake_serialized_lwgeom(lwg_parser_result);\n\n\treturn parser_ferror_occured;\n}\n\nint\nparse_lwg(LWGEOM_PARSER_RESULT *lwg_parser_result, const char* geometry, int flags, allocator allocfunc, report_error errfunc)\n{\n\tthe_geom.lwgi=0;\n\treturn parse_it(lwg_parser_result, geometry, flags, allocfunc, errfunc);\n}\n\nint\nparse_lwgi(LWGEOM_PARSER_RESULT *lwg_parser_result, const char* geometry, int flags, allocator allocfunc, report_error errfunc)\n{\n\tthe_geom.lwgi=1;\n\treturn parse_it(lwg_parser_result, geometry, flags, allocfunc, errfunc);\n}\n\nvoid\nset_zm(char z, char m)\n{\n        LWDEBUGF(2, \"set_zm %d, %d\", z, m);\n\n\tthe_geom.hasZ = z;\n\tthe_geom.hasM = m;\n\tthe_geom.ndims = 2+z+m;\n}\n\n"
  },
  {
    "path": "src/liblwgeom/lwgunparse.c",
    "content": "/*\n * Written by Ralph Mason ralph.mason<at>telogis.com\n *\n * Copyright Telogis 2004\n * www.telogis.com\n *\n * $Id: lwgunparse.c 3639 2009-02-04 00:28:37Z pramsey $\n */\n\n\n#include <string.h>\n#include <math.h>\n#include <stdio.h>\n/* TO get byte order */\n#include <sys/types.h>\n#include <sys/param.h>\n/* Solaris9 does not provide stdint.h */\n/* #include <stdint.h> */\n#include <inttypes.h>\n\n#include \"liblwgeom.h\"\n#include \"wktparse.h\"\n\n\n/*-- Typedefs ---------------------------------------------- */\n\ntypedef uint32_t int4;\ntypedef uchar* (*outfunc)(uchar*,int);\ntypedef uchar* (*outwkbfunc)(uchar*);\n\n/*-- Prototypes -------------------------------------------- */\n\nvoid ensure(int chars);\nvoid to_end(void);\nvoid write_str(const char* str);\nvoid write_double(double val);\nvoid write_int(int i);\nint4 read_int(uchar** geom);\ndouble read_double(uchar** geom);\nuchar* output_point(uchar* geom,int supress);\nuchar* output_single(uchar* geom,int supress);\nuchar* output_collection(uchar* geom,outfunc func,int supress);\nuchar* output_line_collection(uchar* geom,outfunc func,int supress);\nuchar* output_polygon_collection(uchar* geom,int suppress);\nuchar* output_polygon_ring_collection(uchar* geom,outfunc func,int supress);\nuchar* output_circstring_collection(uchar* geom,outfunc func,int supress);\nuchar* output_multipoint(uchar* geom,int suppress);\nuchar* output_compound(uchar* geom, int suppress);\nuchar* output_multisurface(uchar* geom, int suppress);\n\nvoid write_wkb_hex_bytes(uchar* ptr, unsigned int cnt, size_t size);\nvoid write_wkb_bin_bytes(uchar* ptr, unsigned int cnt, size_t size);\nvoid write_wkb_bin_flip_bytes(uchar* ptr, unsigned int cnt, size_t size);\nvoid write_wkb_hex_flip_bytes(uchar* ptr, unsigned int cnt, size_t size);\n\nvoid write_wkb_int(int i);\nuchar* output_wkb_collection(uchar* geom,outwkbfunc func);\nuchar* output_wkb_polygon_collection(uchar* geom);\nuchar* output_wkb_polygon_ring_collection(uchar* geom,outwkbfunc func);\nuchar* output_wkb_line_collection(uchar* geom,outwkbfunc func);\nuchar* output_wkb_circstring_collection(uchar* geom,outwkbfunc func);\nuchar* output_wkb_point(uchar* geom);\nuchar* output_wkb(uchar* geom);\n\n/*-- Globals ----------------------------------------------- */\n\nstatic int unparser_ferror_occured;\nstatic int dims;\nstatic allocator local_malloc;\nstatic freeor local_free;\nstatic char*  out_start;\nstatic char*  out_pos;\nstatic int len;\nstatic int lwgi;\nstatic uchar endianbyte;\nvoid (*write_wkb_bytes)(uchar* ptr,unsigned int cnt,size_t size);\n\n/*\n * Unparser current instance check flags - a bitmap of flags that determine which checks are enabled during the current unparse\n * (see liblwgeom.h for the related PARSER_CHECK constants)\n */\nint current_unparser_check_flags;\n\n/*\n * Unparser current instance result structure - the result structure being used for the current unparse\n */\nLWGEOM_UNPARSER_RESULT *current_lwg_unparser_result;\n\n/*\n * Unparser error messages\n *\n * IMPORTANT: Make sure the order of these messages matches the UNPARSER_ERROR constants in liblwgeom.h!\n * The 0th element should always be empty since it is unused (error constants start from -1)\n */\n\nconst char *unparser_error_messages[] = {\n        \"\",\n        \"geometry requires more points\",\n\t\"geometry must have an odd number of points\",\n        \"geometry contains non-closed rings\"\n};\n\n/* Macro to return the error message and the current position within WKT */\n#define LWGEOM_WKT_UNPARSER_ERROR(errcode) \\\n        do { \\\n\t\tif (!unparser_ferror_occured) { \\\n                \tunparser_ferror_occured = -1 * errcode; \\\n                \tcurrent_lwg_unparser_result->message = unparser_error_messages[errcode]; \\\n                \tcurrent_lwg_unparser_result->errlocation = (out_pos - out_start); \\\n\t\t} \\\n        } while (0);\n\n/* Macro to return the error message and the current position within WKB */\n#define LWGEOM_WKB_UNPARSER_ERROR(errcode) \\\n        do { \\\n\t\tif (!unparser_ferror_occured) { \\\n                \tunparser_ferror_occured = -1 * errcode; \\\n                \tcurrent_lwg_unparser_result->message = unparser_error_messages[errcode]; \\\n                \tcurrent_lwg_unparser_result->errlocation = (out_pos - out_start); \\\n\t\t} \\\n        } while (0);\n\n/*---------------------------------------------------------- */\n\n\n\n\n\n\n/*\n * Ensure there is enough space for chars bytes.\n * Reallocate memory is this is not the case.\n */\nvoid\nensure(int chars){\n\n\tint pos = out_pos - out_start;\n\n\tif (  (pos + chars) >= len ){\n\t\tchar* newp =(char*)local_malloc(len*2);\n\t\tmemcpy(newp,out_start,len);\n\t\tlocal_free(out_start);\n\t\tout_start = newp;\n\t\tout_pos = newp + pos;\n\t\tlen *=2;\n\t}\n}\n\nvoid\nto_end(void)\n{\n\twhile(*out_pos){\n\t\tout_pos++;\n\t}\n}\n\nvoid\nwrite_str(const char* str)\n{\n\tensure(32);\n\tstrcpy(out_pos,str);\n\tto_end();\n}\n\nvoid\nwrite_double(double val){\n\tensure(32);\n\tif (lwgi)\n\t\tsprintf(out_pos,\"%.8g\",val);\n\telse\n\t\tsprintf(out_pos,\"%.15g\",val);\n\tto_end();\n}\n\nvoid\nwrite_int(int i){\n\tensure(32);\n\tsprintf(out_pos,\"%i\",i);\n\tto_end();\n}\n\nint4\nread_int(uchar** geom)\n{\n\tint4 ret;\n#ifdef SHRINK_INTS\n\tif ( getMachineEndian() == NDR ){\n\t\tif( (**geom)& 0x01){\n\t\t\tret = **geom >>1;\n\t\t\t(*geom)++;\n\t\t\treturn ret;\n\t\t}\n\t}\n\telse{\n\t\tif( (**geom)& 0x80){\n\t\t\tret = **geom & ~0x80;\n\t\t\t(*geom)++;\n\t\t\treturn ret;\n\t\t}\n\t}\n#endif\n\tmemcpy(&ret,*geom,4);\n\n#ifdef SHRINK_INTS\n\tif ( getMachineEndian() == NDR ){\n\t\tret >>= 1;\n\t}\n#endif\n\n\t(*geom)+=4;\n\treturn ret;\n}\n\ndouble round(double);\n\ndouble read_double(uchar** geom){\n\tif (lwgi){\n\t\tdouble ret = *((int4*)*geom);\n\t\tret /= 0xb60b60;\n\t\t(*geom)+=4;\n\t\treturn ret-180.0;\n\t}\n\telse{\n\t\tdouble ret;\n \t\tmemcpy(&ret, *geom, 8);\n\t\t(*geom)+=8;\n\t\treturn ret;\n\t}\n}\n           \nuchar *\noutput_point(uchar* geom,int supress)\n{\n\tint i;\n\n\tfor( i = 0 ; i < dims ; i++ ){\n\t\twrite_double(read_double(&geom));\n\t\tif (i +1 < dims )\n\t\t\twrite_str(\" \");\n\t}\n\treturn geom;\n}\n\nuchar *\noutput_single(uchar* geom,int supress)\n{\n\twrite_str(\"(\");\n\tgeom=output_point(geom,supress);\n\twrite_str(\")\");\n\treturn geom;\n}\n\n/* Output a standard collection */\nuchar *\noutput_collection(uchar* geom,outfunc func,int supress)\n{\n\tint cnt = read_int(&geom);\n\tif ( cnt == 0 ){\n\t\twrite_str(\" EMPTY\");\n\t}\n\telse{\n\t\twrite_str(\"(\");\n\t\twhile(cnt--){\n\t\t\tgeom=func(geom,supress);\n\t\t\tif ( cnt ){\n\t\t\t\twrite_str(\",\");\n\t\t\t}\n\t\t}\n\t\twrite_str(\")\");\n\t}\n\treturn geom;\n}\n\n/* Output a set of LINESTRING points */\nuchar *\noutput_line_collection(uchar* geom,outfunc func,int supress)\n{\n\tint cnt = read_int(&geom);\n\tint orig_cnt = cnt;\n\n\tif ( cnt == 0 ){\n\t\twrite_str(\" EMPTY\");\n\t}\n\telse{\n\t\twrite_str(\"(\");\n\t\twhile(cnt--){\n\t\t\tgeom=func(geom,supress);\n\t\t\tif ( cnt ){\n\t\t\t\twrite_str(\",\");\n\t\t\t}\n\t\t}\n\t\twrite_str(\")\");\n\t}\n\n\t/* Ensure that LINESTRING has a minimum of 2 points */\n\tif ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 2)\n\t\tLWGEOM_WKT_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);\n\n\treturn geom;\n}\n\n/* Output an individual ring from a POLYGON  */\nuchar *\noutput_polygon_ring_collection(uchar* geom,outfunc func,int supress)\n{\n        uchar *temp;\n        int dimcount;\n        double first_point[dims];\n        double last_point[dims];\n\n\tint cnt = read_int(&geom);\n\tint orig_cnt = cnt;\n\tif ( cnt == 0 ){\n\t\twrite_str(\" EMPTY\");\n\t}\n\telse{\n\t\twrite_str(\"(\");\n\t\n        \t/* Store the first point of the ring (use a temp var since read_double alters\n           \tthe pointer after use) */\n        \ttemp = geom;\n        \tdimcount = 0;\n        \twhile (dimcount < dims)\n        \t{\n                \tfirst_point[dimcount] = read_double(&temp);\n                \tdimcount++;\n        \t}\n\t\n\t\twhile(cnt--){\n\t\t\tgeom=func(geom,supress);\n\t\t\tif ( cnt ){\n\t\t\t\twrite_str(\",\");\n\t\t\t}\n\t\t}\n\t\twrite_str(\")\");\n\n        \t/* Store the last point of the ring (note: we will have moved past it, so we\n           \tneed to count backwards) */\n        \ttemp = geom - sizeof(double) * dims;\n        \tdimcount = 0;\n        \twhile (dimcount < dims)\n        \t{\n                \tlast_point[dimcount] = read_double(&temp);\n                \tdimcount++;\n       \t \t}\n\n        \t/* Check if they are the same... */\n        \tif (memcmp(&first_point, &last_point, sizeof(double) * dims) &&\n\t\t\t(current_unparser_check_flags & PARSER_CHECK_CLOSURE))\n                \tLWGEOM_WKT_UNPARSER_ERROR(UNPARSER_ERROR_UNCLOSED);\t\n\n\t\t/* Ensure that POLYGON has a minimum of 4 points */\n        \tif ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 4)\n                \tLWGEOM_WKT_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);\n\t}\n\treturn geom;\n}\n\n/* Ouput the points from a CIRCULARSTRING */\nuchar *\noutput_circstring_collection(uchar* geom,outfunc func,int supress)\n{\n\tint cnt = read_int(&geom);\n\tint orig_cnt = cnt;\n\n\tif ( cnt == 0 ){\n\t\twrite_str(\" EMPTY\");\n\t}\n\telse{\n\t\twrite_str(\"(\");\n\t\twhile(cnt--){\n\t\t\tgeom=func(geom,supress);\n\t\t\tif ( cnt ){\n\t\t\t\twrite_str(\",\");\n\t\t\t}\n\t\t}\n\t\twrite_str(\")\");\n\t}\n\n\t/* Ensure that a CIRCULARSTRING has a minimum of 3 points */\n        if ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 3) {\n                LWGEOM_WKT_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);\n\t}\n\n\t/* Ensure that a CIRCULARSTRING has an odd number of points */\n        if ((current_unparser_check_flags & PARSER_CHECK_ODD) && orig_cnt % 2 != 1) {\n                LWGEOM_WKT_UNPARSER_ERROR(UNPARSER_ERROR_ODDPOINTS);\n\t}\n\n\treturn geom;\n}\n\n/* Output a POLYGON consisting of a number of rings */\nuchar *\noutput_polygon_collection(uchar* geom,int suppress)\n{\n\treturn output_polygon_ring_collection(geom,output_point,suppress);\n}\n\nuchar *output_wkt(uchar* geom, int supress);\n\n/* special case for multipoint to supress extra brackets */\nuchar *output_multipoint(uchar* geom,int suppress){\n\tunsigned char type = *geom & 0x0f;\n\t\n\tif ( type  == POINTTYPE )\n\t\treturn output_point(++geom,suppress);\n\telse if ( type == POINTTYPEI ){\n\t\tlwgi++;\n\t\tgeom=output_point(++geom,0);\n\t\tlwgi--;\n\t\treturn geom;\n\t}\n\t\n\treturn output_wkt(geom,suppress);\n}\n\n/* Special case for compound curves: suppress the LINESTRING prefix from a curve if it appears as\n   a component of a COMPOUNDCURVE, but not CIRCULARSTRING */\nuchar *output_compound(uchar* geom, int suppress) {\n        unsigned char type;\n\n        LWDEBUG(2, \"output_compound called.\");\n\n        type=*geom;\n        switch(TYPE_GETTYPE(type)) \n        {\n                case LINETYPE:\n                        geom = output_wkt(geom,2);\n                        break;\n                case CIRCSTRINGTYPE:\n                        geom = output_wkt(geom,1);\n                        break;\n        }\n\treturn geom;\n}\n\n/* Special case for multisurfaces: suppress the POLYGON prefix from a surface if it appears as\n   a component of a MULTISURFACE, but not CURVEPOLYGON */\nuchar *output_multisurface(uchar* geom, int suppress) {\n        unsigned char type;\n\n        LWDEBUG(2, \"output_multisurface called.\");\n\n        type=*geom;\n        switch(TYPE_GETTYPE(type))\n        {\n                case POLYGONTYPE:\n                        geom = output_wkt(geom,2);\n                        break;\n                case CURVEPOLYTYPE:\n                        geom = output_wkt(geom,1);\n                        break;\n        }\n        return geom;\n}\n\n/*\n * Suppress=0 -- write TYPE, M, coords\n * Suppress=1 -- write TYPE, coords \n * Suppress=2 -- write only coords\n */\nuchar *\noutput_wkt(uchar* geom, int supress)\n{\n\n\tunsigned char type=*geom++;\n\tchar writeM=0;\n\tdims = TYPE_NDIMS(type); /* ((type & 0x30) >> 4)+2; */\n\n        LWDEBUG(2, \"output_wkt called.\");\n\n\tif ( ! supress && !TYPE_HASZ(type) && TYPE_HASM(type) ) writeM=1;\n\n\n\t/* Skip the bounding box if there is one */\n\tif ( TYPE_HASBBOX(type) )\n\t{\n\t\tgeom+=16;\n\t}\n\n\tif ( TYPE_HASSRID(type) ) {\n\t\twrite_str(\"SRID=\");write_int(read_int(&geom));write_str(\";\");\n\t}\n\n\tswitch(TYPE_GETTYPE(type)) {\n\t\tcase POINTTYPE:\n\t\t\tif ( supress < 2 )\n\t\t\t{\n\t\t\t\tif (writeM) write_str(\"POINTM\");\n\t\t\t\telse write_str(\"POINT\");\n\t\t\t}\n\t\t\tgeom=output_single(geom,0);\n\t\t\tbreak;\n\t\tcase LINETYPE:\n\t\t\tif ( supress < 2 )\n\t\t\t{\n\t\t\t\tif (writeM) write_str(\"LINESTRINGM\");\n\t\t\t\telse write_str(\"LINESTRING\");\n\t\t\t}\n\t\t\tgeom = output_line_collection(geom,output_point,0);\n\t\t\tbreak;\n                case CIRCSTRINGTYPE:\n                        if ( supress < 2 )\n                        {\n                                if(writeM) write_str(\"CIRCULARSTRINGM\");\n                                else write_str(\"CIRCULARSTRING\");\n                        }\n                        geom = output_circstring_collection(geom,output_point,0);\n                        break;\n\t\tcase POLYGONTYPE:\n\t\t\tif ( supress < 2 )\n\t\t\t{\n\t\t\t\tif (writeM) write_str(\"POLYGONM\");\n\t\t\t\telse write_str(\"POLYGON\");\n\t\t\t}\n\t\t\tgeom = output_collection(geom,output_polygon_collection,0);\n\t\t\tbreak;\n                case COMPOUNDTYPE:\n                        if ( supress < 2 )\n                        {\n                                if (writeM) write_str(\"COMPOUNDCURVEM\");\n                                else write_str(\"COMPOUNDCURVE\");\n                        }\n                        geom = output_collection(geom, output_compound,1);\n                        break;\n                case CURVEPOLYTYPE:\n                        if (supress < 2)\n                        {\n                                if(writeM) write_str(\"CURVEPOLYGONM\");\n                                else write_str(\"CURVEPOLYGON\");\n                        }\n                        geom = output_collection(geom, output_compound,0);\n                        break;\n\t\tcase MULTIPOINTTYPE:\n\t\t\tif ( supress < 2 )\n\t\t\t{\n\t\t\t\tif (writeM) write_str(\"MULTIPOINTM\");\n\t\t\t\telse write_str(\"MULTIPOINT\");\n\t\t\t}\n\t\t\tgeom = output_collection(geom,output_multipoint,2);\n\t\t\tbreak;\n\t\tcase MULTILINETYPE:\n\t\t\tif ( supress < 2 )\n\t\t\t{\n\t\t\t\tif (writeM) write_str(\"MULTILINESTRINGM\");\n\t\t\t\telse write_str(\"MULTILINESTRING\");\n\t\t\t}\n\t\t\tgeom = output_collection(geom,output_wkt,2);\n\t\t\tbreak;\n                case MULTICURVETYPE:\n                        if ( supress < 2 )\n                        {\n                                if (writeM) write_str(\"MULTICURVEM\");\n                                else write_str(\"MULTICURVE\");\n                        }\n                        geom = output_collection(geom,output_compound,2);\n                        break;\n\t\tcase MULTIPOLYGONTYPE:\n\t\t\tif ( supress < 2 )\n\t\t\t{\n\t\t\t\tif (writeM) write_str(\"MULTIPOLYGONM\");\n\t\t\t\telse write_str(\"MULTIPOLYGON\");\n\t\t\t}\n\t\t\tgeom = output_collection(geom,output_wkt,2);\n\t\t\tbreak;\n                case MULTISURFACETYPE:\n                        if ( supress < 2)\n                        {\n                                if (writeM) write_str(\"MULTISURFACEM\");\n                                else write_str(\"MULTISURFACE\");\n                        } \n                        geom = output_collection(geom,output_multisurface,2);\n                        break;\n\t\tcase COLLECTIONTYPE:\n\t\t\tif ( supress < 2 )\n\t\t\t{\n\t\t\t\tif (writeM) write_str(\"GEOMETRYCOLLECTIONM\");\n\t\t\t\telse write_str(\"GEOMETRYCOLLECTION\");\n\t\t\t}\n\t\t\tgeom = output_collection(geom,output_wkt,1);\n\t\t\tbreak;\n\n\t\tcase POINTTYPEI:\n\t\t\tif ( supress < 2 )\n\t\t\t{\n\t\t\t\tif (writeM) write_str(\"POINTM\");\n\t\t\t\telse write_str(\"POINT\");\n\t\t\t}\n\t\t\tlwgi++;\n\t\t\tgeom=output_single(geom,0);\n\t\t\tlwgi--;\n\t\t\tbreak;\n\t\tcase LINETYPEI:\n\t\t\tif ( supress < 2 )\n\t\t\t{\n\t\t\t\tif (writeM) write_str(\"LINESTRINGM\");\n\t\t\t\telse write_str(\"LINESTRING\");\n\t\t\t}\n\t\t\tlwgi++;\n\t\t\tgeom = output_collection(geom,output_point,0);\n\t\t\tlwgi--;\n\t\t\tbreak;\n\t\tcase POLYGONTYPEI:\n\t\t\tif ( supress < 2 )\n\t\t\t{\n\t\t\t\tif (writeM) write_str(\"POLYGONM\");\n\t\t\t\telse write_str(\"POLYGON\");\n\t\t\t}\n\t\t\tlwgi++;\n\t\t\tgeom = output_collection(geom,output_polygon_collection,0);\n\t\t\tlwgi--;\n\t\t\tbreak;\n\t}\n\treturn geom;\n}\n\nint\nunparse_WKT(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar* serialized, allocator alloc, freeor free, int flags)\n{\n\n        LWDEBUGF(2, \"unparse_WKT called with parser flags %d.\", flags);\n\n\tif (serialized==NULL)\n\t\treturn 0;\n\n\t/* Setup the inital parser flags and empty the return struct */\n\tcurrent_lwg_unparser_result = lwg_unparser_result;\n        current_unparser_check_flags = flags;\n\tlwg_unparser_result->wkoutput = NULL;\n        lwg_unparser_result->size = 0;\n\tlwg_unparser_result->serialized_lwgeom = serialized;\n\n\tunparser_ferror_occured = 0;\n\tlocal_malloc=alloc;\n\tlocal_free=free;\n\tlen = 128;\n\tout_start = out_pos = alloc(len);\n\tlwgi=0;\n\n\toutput_wkt(serialized, 0);\n\n\t/* Store the result in the struct */\n\tlwg_unparser_result->wkoutput = out_start;\n\tlwg_unparser_result->size = strlen(out_start);\n\n\treturn unparser_ferror_occured;\n}\n\nstatic char outchr[]={\"0123456789ABCDEF\" };\n\n/* Write HEX bytes flipping */\nvoid\nwrite_wkb_hex_flip_bytes(uchar* ptr, unsigned int cnt, size_t size)\n{\n\tunsigned int bc; /* byte count */\n\n\tensure(cnt*2*size);\n\n\twhile(cnt--){\n\t\tfor(bc=size; bc; bc--)\n\t\t{\n\t\t\t*out_pos++ = outchr[ptr[bc-1]>>4];\n\t\t\t*out_pos++ = outchr[ptr[bc-1]&0x0F];\n\t\t}\n\t\tptr+=size;\n\t}\n}\n\n/* Write HEX bytes w/out flipping */\nvoid\nwrite_wkb_hex_bytes(uchar* ptr, unsigned int cnt, size_t size)\n{\n\tunsigned int bc; /* byte count */\n\n\tensure(cnt*2*size);\n\n\twhile(cnt--){\n\t\tfor(bc=0; bc<size; bc++)\n\t\t{\n\t\t\t*out_pos++ = outchr[ptr[bc]>>4];\n\t\t\t*out_pos++ = outchr[ptr[bc]&0x0F];\n\t\t}\n\t\tptr+=size;\n\t}\n}\n\n/* Write BIN bytes flipping */\nvoid\nwrite_wkb_bin_flip_bytes(uchar* ptr, unsigned int cnt, size_t size)\n{\n\tunsigned int bc; /* byte count */\n\n\tensure(cnt*size);\n\n\twhile(cnt--)\n\t{\n\t\tfor(bc=size; bc; bc--)\n\t\t\t*out_pos++ = ptr[bc-1];\n\t\tptr+=size;\n\t}\n}\n\n\n/* Write BIN bytes w/out flipping */\nvoid\nwrite_wkb_bin_bytes(uchar* ptr, unsigned int cnt, size_t size)\n{\n\tunsigned int bc; /* byte count */\n\n\tensure(cnt*size);\n\n\t/* Could just use a memcpy here ... */\n\twhile(cnt--)\n\t{\n\t\tfor(bc=0; bc<size; bc++)\n\t\t\t*out_pos++ = ptr[bc];\n\t\tptr+=size;\n\t}\n}\n\nuchar *\noutput_wkb_point(uchar* geom)\n{\n\tif ( lwgi ){\n\t\twrite_wkb_bytes(geom,dims,4);\n\t\treturn geom + (4*dims);\n\t}\n\telse{\n\t\twrite_wkb_bytes(geom,dims,8);\n\t\treturn geom + (8*dims);\n\t}\n}\n\nvoid\nwrite_wkb_int(int i){\n\twrite_wkb_bytes((uchar*)&i,1,4);\n}\n\n/* Output a standard collection */\nuchar *\noutput_wkb_collection(uchar* geom,outwkbfunc func)\n{\n\tint cnt = read_int(&geom);\n\n\tLWDEBUGF(2, \"output_wkb_collection: %d iterations loop\", cnt);\n\n\twrite_wkb_int(cnt);\n\twhile(cnt--) geom=func(geom);\n\treturn geom;\n}\n\n/* Output a set of LINESTRING points */\nuchar *\noutput_wkb_line_collection(uchar* geom,outwkbfunc func)\n{\n\tint cnt = read_int(&geom);\n\tint orig_cnt = cnt;\n\n\tLWDEBUGF(2, \"output_wkb_line_collection: %d iterations loop\", cnt);\n\n\twrite_wkb_int(cnt);\n\twhile(cnt--) geom=func(geom);\n\n\t/* Ensure that LINESTRING has a minimum of 2 points */\n        if ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 2) {\n\t\tLWGEOM_WKB_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);\n\t}\n\n\treturn geom;\n}\n\n/* Output an individual ring from a POLYGON  */\nuchar *\noutput_wkb_polygon_ring_collection(uchar* geom,outwkbfunc func)\n{\n\tuchar *temp;\n\tint dimcount;\n\tdouble first_point[dims];\n\tdouble last_point[dims];\n\n\tint cnt = read_int(&geom);\n\tint orig_cnt = cnt;\n\n\tLWDEBUGF(2, \"output_wkb_polygon_ring_collection: %d iterations loop\", cnt);\n\n\twrite_wkb_int(cnt);\n\n\t/* Store the first point of the ring (use a temp var since read_double alters \n\t   the pointer after use) */\n\ttemp = geom;\n\tdimcount = 0;\n\twhile (dimcount < dims)\n\t{\n\t\tfirst_point[dimcount] = read_double(&temp);\n\t\tdimcount++;\n\t}\n\n\twhile(cnt--) geom=func(geom); \n\n\t/* Store the last point of the ring (note: we will have moved past it, so we\n\t   need to count backwards) */\n\ttemp = geom - sizeof(double) * dims;\n\tdimcount = 0;\n\twhile (dimcount < dims)\n\t{\n\t\tlast_point[dimcount] = read_double(&temp);\n\t\tdimcount++;\n\t}\n\n\t/* Check if they are the same... */\n\tif (memcmp(&first_point, &last_point, sizeof(double) * dims) &&\n\t\t(current_unparser_check_flags & PARSER_CHECK_CLOSURE)) {\n\t\tLWGEOM_WKB_UNPARSER_ERROR(UNPARSER_ERROR_UNCLOSED);\n\t}\n\n\t/* Ensure that POLYGON has a minimum of 4 points */\n\tif ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 4)\n\t\tLWGEOM_WKT_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);\n\n\treturn geom;\n}\n\n/* Output a POLYGON consisting of a number of rings */\nuchar *\noutput_wkb_polygon_collection(uchar* geom)\n{\n\tLWDEBUG(2, \"output_wkb_polygon_collection\");\n\n\treturn output_wkb_polygon_ring_collection(geom,output_wkb_point); \n}\n\n/* Ouput the points from a CIRCULARSTRING */\nuchar *\noutput_wkb_circstring_collection(uchar* geom,outwkbfunc func)\n{\n\tint cnt = read_int(&geom);\n\tint orig_cnt = cnt;\n\n\tLWDEBUGF(2, \"output_wkb_curve_collection: %d iterations loop\", cnt);\n\n\twrite_wkb_int(cnt);\n\twhile(cnt--) geom=func(geom);\n\n\t/* Ensure that a CIRCULARSTRING has a minimum of 3 points */\n        if ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 3) {\n\t\tLWGEOM_WKB_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);\n\t}\n\n\t/* Ensure that a CIRCULARSTRING has an odd number of points */\n        if ((current_unparser_check_flags & PARSER_CHECK_ODD) && orig_cnt % 2 != 1) {\n\t\tLWGEOM_WKB_UNPARSER_ERROR(UNPARSER_ERROR_ODDPOINTS);\n\t}\n\n\treturn geom;\n}\n\nuchar *\noutput_wkb(uchar* geom)\n{\n\tunsigned char type=*geom++;\n\tint4 wkbtype;\n\n\tdims = TYPE_NDIMS(type); \n\n\tLWDEBUGF(2, \"output_wkb: dims set to %d\", dims);\n\n\t/* Skip the bounding box */\n\tif ( TYPE_HASBBOX(type) ) { \n\t\tgeom+=16;\n\t}\n\n\twkbtype = TYPE_GETTYPE(type); \n\n\tif ( TYPE_HASZ(type) )\n\t\t wkbtype |= WKBZOFFSET;\n\tif ( TYPE_HASM(type) )\n\t\t wkbtype |= WKBMOFFSET;\n\tif ( TYPE_HASSRID(type) ) {\n\t\twkbtype |= WKBSRIDFLAG;\n\t}\n\n\n\t/* Write byteorder (as from WKB specs...) */\n\twrite_wkb_bytes(&endianbyte,1,1);\n\n\twrite_wkb_int(wkbtype);\n\n\tif ( TYPE_HASSRID(type) ) {\n\t\twrite_wkb_int(read_int(&geom));\n\t}\n\n\tswitch(TYPE_GETTYPE(type)){\n\t\tcase POINTTYPE:\n\t\t\tgeom=output_wkb_point(geom);\n\t\t\tbreak;\n\t\tcase LINETYPE:\n\t\t\tgeom=output_wkb_line_collection(geom,output_wkb_point);\n\t\t\tbreak;\n                case CIRCSTRINGTYPE:\n                        geom=output_wkb_circstring_collection(geom,output_wkb_point);\n                        break;\n\t\tcase POLYGONTYPE:\n\t\t\tgeom=output_wkb_collection(geom,output_wkb_polygon_collection);\n\t\t\tbreak;\n                case COMPOUNDTYPE:\n                        geom=output_wkb_collection(geom,output_wkb);\n                        break;\n                case CURVEPOLYTYPE:\n                        geom=output_wkb_collection(geom,output_wkb);\n                        break;\n                case MULTICURVETYPE:\n                case MULTISURFACETYPE:\n\t\tcase MULTIPOINTTYPE:\n\t\tcase MULTILINETYPE:\n\t\tcase MULTIPOLYGONTYPE:\n\t\tcase COLLECTIONTYPE:\n\t\t\tgeom = output_wkb_collection(geom,output_wkb);\n\t\t\tbreak;\n\n\t\t/*\n\t\t\tThese don't output standard wkb at the moment\n\t\t\tthe output and integer version.\n\n\t\t\thowever you could run it through the wkt parser\n\t\t\tfor a lwg and then output that.  There should\n\t\t\talso be a force_to_real_(lwgi)\n\t\t*/\n\t\tcase POINTTYPEI:\n\t\t\tlwgi++;\n\t\t\tgeom=output_wkb_point(geom);\n\t\t\tlwgi--;\n\t\t\tbreak;\n\t\tcase LINETYPEI:\n\t\t\tlwgi++;\n\t\t\tgeom = output_wkb_collection(geom,output_wkb_point);\n\t\t\tlwgi--;\n\t\t\tbreak;\n\t\tcase POLYGONTYPEI:\n\t\t\tlwgi++;\n\t\t\tgeom = output_wkb_collection(geom,output_wkb_polygon_collection);\n\t\t\tlwgi--;\n\t\t\tbreak;\n\t}\n\treturn geom;\n}\n\nint\nunparse_WKB(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar* serialized, allocator alloc, freeor free, int flags, char endian, uchar hex)\n{\n\tLWDEBUGF(2, \"unparse_WKB(%p,...) called with parser flags %d\", serialized, flags);\n\n\tif (serialized==0)\n\t\treturn 0;\n\n\t/* Setup the inital parser flags and empty the return struct */\n\tcurrent_lwg_unparser_result = lwg_unparser_result;\n        current_unparser_check_flags = flags;\n\tlwg_unparser_result->wkoutput = NULL;\n\tlwg_unparser_result->size = 0;\n\tlwg_unparser_result->serialized_lwgeom = serialized;\n\n\tunparser_ferror_occured = 0;\n\tlocal_malloc=alloc;\n\tlocal_free=free;\n\tlen = 128;\n\tout_start = out_pos = alloc(len);\n\tlwgi=0;\n\n\tif ( endian == (char)-1 )\n\t{\n\t\tendianbyte = getMachineEndian();\n\t\tif ( hex ) write_wkb_bytes = write_wkb_hex_bytes;\n\t\telse write_wkb_bytes = write_wkb_bin_bytes;\n\t}\n\telse\n\t{\n\t\tendianbyte = endian;\n\t\tif ( endianbyte != getMachineEndian() )\n\t\t{\n\t\t\tif ( hex ) write_wkb_bytes = write_wkb_hex_flip_bytes;\n\t\t\telse write_wkb_bytes = write_wkb_bin_flip_bytes;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( hex ) write_wkb_bytes = write_wkb_hex_bytes;\n\t\t\telse write_wkb_bytes = write_wkb_bin_bytes;\n\t\t}\n\t}\n\n\toutput_wkb(serialized);\n\n\tif ( hex ) {\n\t\tensure(1);\n\t\t*out_pos=0;\n\t}\n\n\t/* Store the result in the struct */\t\n\tlwg_unparser_result->wkoutput = out_start;\n\tlwg_unparser_result->size = (out_pos-out_start);\n\n\treturn unparser_ferror_occured;\t\n}\n\n\n/******************************************************************\n * $Log$\n * Revision 1.23  2006/02/06 11:12:22  strk\n * uint32_t typedef moved back from wktparse.h to lwgparse.c and wktunparse.c\n *\n * Revision 1.22  2006/02/03 20:53:37  strk\n * Swapped stdint.h (unavailable on Solaris9) with inttypes.h\n *\n * Revision 1.21  2006/02/03 09:52:14  strk\n * Changed int4 typedefs to use POSIX uint32_t\n *\n * Revision 1.20  2006/01/09 15:12:02  strk\n * ISO C90 comments\n *\n * Revision 1.19  2005/03/10 18:19:16  strk\n * Made void args explicit to make newer compilers happy\n *\n * Revision 1.18  2005/02/21 16:16:14  strk\n * Changed byte to uchar to avoid clashes with win32 headers.\n *\n * Revision 1.17  2005/02/07 13:21:10  strk\n * Replaced DEBUG* macros with PGIS_DEBUG*, to avoid clashes with postgresql DEBUG\n *\n * Revision 1.16  2005/01/18 09:32:03  strk\n * Changed unparse_WKB interface to take an output size pointer and an HEXFORM\n * specifier. Reworked code in wktunparse to use function pointers.\n *\n * Revision 1.15  2004/12/21 15:19:01  strk\n * Canonical binary reverted back to EWKB, now supporting SRID inclusion.\n *\n * Revision 1.14  2004/12/17 11:08:53  strk\n * Moved getMachineEndian from parser to liblwgeom.{h,c}.\n * Added XDR and NDR defines.\n * Fixed all usage of them.\n *\n * Revision 1.13  2004/10/25 12:27:33  strk\n * Removed useless network type includes,\n * Added param.h include for BYTE_ORDER defines under win32.\n *\n * Revision 1.12  2004/10/21 19:48:34  strk\n * Stricter syntax fixes. Reported by Sbastien NICAISE <snicaise@iciatechnologies.com>\n *\n * Revision 1.11  2004/10/15 07:35:41  strk\n * Fixed a bug introduced by me (byteorder skipped for inner geoms in WKB)\n *\n * Revision 1.10  2004/10/11 14:03:33  strk\n * Added endiannes specification to unparse_WKB, AsBinary, lwgeom_to_wkb.\n *\n ******************************************************************/\n"
  },
  {
    "path": "src/liblwgeom/lwline.c",
    "content": "/**********************************************************************\n * $Id: lwline.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n/* basic LWLINE functions */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"liblwgeom.h\"\n\n\n\n/*\n * Construct a new LWLINE.  points will *NOT* be copied\n * use SRID=-1 for unknown SRID (will have 8bit type's S = 0)\n */\nLWLINE *\nlwline_construct(int SRID, BOX2DFLOAT4 *bbox, POINTARRAY *points)\n{\n\tLWLINE *result;\n\tresult = (LWLINE*) lwalloc(sizeof(LWLINE));\n\n        LWDEBUG(2, \"lwline_construct called.\");\n\n\tresult->type = lwgeom_makeType_full(\n\t\tTYPE_HASZ(points->dims),\n\t\tTYPE_HASM(points->dims),\n\t\t(SRID!=-1), LINETYPE,\n\t\t0);\n\n        LWDEBUGF(3, \"lwline_construct type=%d\", result->type);\n\n\tresult->SRID = SRID;\n\tresult->points = points;\n\tresult->bbox = bbox;\n\n\treturn result;\n}\n\n/*\n * given the LWGEOM serialized form (or a pointer into a muli* one)\n * construct a proper LWLINE.\n * serialized_form should point to the 8bit type format (with type = 2)\n * See serialized form doc\n */\nLWLINE *\nlwline_deserialize(uchar *serialized_form)\n{\n\tuchar type;\n\tLWLINE *result;\n\tuchar *loc =NULL;\n\tuint32 npoints;\n\tPOINTARRAY *pa;\n\n\ttype = (uchar) serialized_form[0];\n\n\tif ( lwgeom_getType(type) != LINETYPE)\n\t{\n\t\tlwerror(\"lwline_deserialize: attempt to deserialize a line which is really a %s\", lwgeom_typename(type));\n\t\treturn NULL;\n\t}\n\n\tresult = (LWLINE*) lwalloc(sizeof(LWLINE)) ;\n\tresult->type = type;\n\n\tloc = serialized_form+1;\n\n\tif (lwgeom_hasBBOX(type))\n\t{\n\t\tLWDEBUG(3, \"lwline_deserialize: input has bbox\");\n\n\t\tresult->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n\t\tmemcpy(result->bbox, loc, sizeof(BOX2DFLOAT4));\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t}\n\telse\n\t{\n\t\tresult->bbox = NULL;\n\t\t/*lwnotice(\"line has NO bbox\"); */\n\t}\n\n\tif ( lwgeom_hasSRID(type))\n\t{\n\t\t/*lwnotice(\"line has srid\"); */\n\t\tresult->SRID = lw_get_int32(loc);\n\t\tloc +=4; /* type + SRID */\n\t}\n\telse\n\t{\n\t\t/*lwnotice(\"line has NO srid\"); */\n\t\tresult->SRID = -1;\n\t}\n\n\t/* we've read the type (1 byte) and SRID (4 bytes, if present) */\n\n\tnpoints = lw_get_uint32(loc);\n\t/*lwnotice(\"line npoints = %d\", npoints); */\n\tloc +=4;\n\tpa = pointArray_construct(loc, TYPE_HASZ(type), TYPE_HASM(type), npoints);\n\tresult->points = pa;\n\n\treturn result;\n}\n\n/*\n * convert this line into its serialize form\n * result's first char will be the 8bit type.  See serialized form doc\n */\nuchar *\nlwline_serialize(LWLINE *line)\n{\n\tsize_t size, retsize;\n\tuchar * result;\n\n\tif (line == NULL) lwerror(\"lwline_serialize:: given null line\");\n\n\tsize = lwline_serialize_size(line);\n\tresult = lwalloc(size);\n\tlwline_serialize_buf(line, result, &retsize);\n\n\tif ( retsize != size )\n\t{\n\t\tlwerror(\"lwline_serialize_size returned %d, ..serialize_buf returned %d\", size, retsize);\n\t}\n\n\treturn result;\n}\n\n/*\n * convert this line into its serialize form writing it into\n * the given buffer, and returning number of bytes written into\n * the given int pointer.\n * result's first char will be the 8bit type.  See serialized form doc\n */\nvoid\nlwline_serialize_buf(LWLINE *line, uchar *buf, size_t *retsize)\n{\n\tchar hasSRID;\n\tuchar *loc;\n\tint ptsize;\n\tsize_t size;\n\n\tLWDEBUGF(2, \"lwline_serialize_buf(%p, %p, %p) called\",\n\t\tline, buf, retsize);\n\n\tif (line == NULL)\n\t\tlwerror(\"lwline_serialize:: given null line\");\n\n\tif ( TYPE_GETZM(line->type) != TYPE_GETZM(line->points->dims) )\n\t\tlwerror(\"Dimensions mismatch in lwline\");\n\n\tptsize = pointArray_ptsize(line->points);\n\n\thasSRID = (line->SRID != -1);\n\n\tbuf[0] = (uchar) lwgeom_makeType_full(\n\t\tTYPE_HASZ(line->type), TYPE_HASM(line->type),\n\t\thasSRID, LINETYPE, line->bbox ? 1 : 0);\n\tloc = buf+1;\n\n\tLWDEBUGF(3, \"lwline_serialize_buf added type (%d)\", line->type);\n\n\tif (line->bbox)\n\t{\n\t\tmemcpy(loc, line->bbox, sizeof(BOX2DFLOAT4));\n\t\tloc += sizeof(BOX2DFLOAT4);\n\n\t\tLWDEBUG(3, \"lwline_serialize_buf added BBOX\");\n\t}\n\n\tif (hasSRID)\n\t{\n\t\tmemcpy(loc, &line->SRID, sizeof(int32));\n\t\tloc += sizeof(int32);\n\n\t\tLWDEBUG(3, \"lwline_serialize_buf added SRID\");\n\t}\n\n\tmemcpy(loc, &line->points->npoints, sizeof(uint32));\n\tloc += sizeof(uint32);\n\n\tLWDEBUGF(3, \"lwline_serialize_buf added npoints (%d)\",\n\t\tline->points->npoints);\n\n\t/*copy in points */\n\tsize = line->points->npoints*ptsize;\n\tmemcpy(loc, getPoint_internal(line->points, 0), size);\n\tloc += size;\n\n\tLWDEBUGF(3, \"lwline_serialize_buf copied serialized_pointlist (%d bytes)\",\n\t\tptsize * line->points->npoints);\n\n\tif (retsize) *retsize = loc-buf;\n\n\t/*printBYTES((uchar *)result, loc-buf); */\n\n\tLWDEBUGF(3, \"lwline_serialize_buf returning (loc: %p, size: %d)\",\n\t\tloc, loc-buf);\n}\n\n/*\n * Find bounding box (standard one) \n * zmin=zmax=NO_Z_VALUE if 2d \n */\nBOX3D *\nlwline_compute_box3d(LWLINE *line)\n{\n\tBOX3D *ret;\n\n\tif (line == NULL) return NULL;\n\n\tret = ptarray_compute_box3d(line->points);\n\treturn ret;\n}\n\n/* find length of this deserialized line */\nsize_t\nlwline_serialize_size(LWLINE *line)\n{\n\tsize_t size = 1;  /* type */\n\n\tLWDEBUG(2, \"lwline_serialize_size called\");\n\n\tif ( line->SRID != -1 ) size += 4; /* SRID */\n\tif ( line->bbox ) size += sizeof(BOX2DFLOAT4);\n\n\tsize += 4; /* npoints */\n\tsize += pointArray_ptsize(line->points)*line->points->npoints;\n\n\tLWDEBUGF(3, \"lwline_serialize_size returning %d\", size);\n\n\treturn size;\n}\n\nvoid lwline_free (LWLINE  *line)\n{\n\tif ( line->bbox ) \n\t\tlwfree(line->bbox);\n\n\tptarray_free(line->points);\n\tlwfree(line);\n}\n\n/* find length of this serialized line */\nsize_t\nlwgeom_size_line(const uchar *serialized_line)\n{\n\tint type = (uchar) serialized_line[0];\n\tuint32 result = 1;  /*type */\n\tconst uchar *loc;\n\tuint32 npoints;\n\n\tLWDEBUG(2, \"lwgeom_size_line called\");\n\n\tif ( lwgeom_getType(type) != LINETYPE)\n\t\tlwerror(\"lwgeom_size_line::attempt to find the length of a non-line\");\n\n\n\tloc = serialized_line+1;\n\n\tif (lwgeom_hasBBOX(type))\n\t{\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t\tresult +=sizeof(BOX2DFLOAT4);\n\t}\n\n\tif ( lwgeom_hasSRID(type))\n\t{\n\t\tloc += 4; /* type + SRID */\n\t\tresult +=4;\n\t}\n\n\t/* we've read the type (1 byte) and SRID (4 bytes, if present) */\n\tnpoints = lw_get_uint32(loc);\n\tresult += sizeof(uint32); /* npoints */\n\n\tresult += TYPE_NDIMS(type) * sizeof(double) * npoints;\n\n\tLWDEBUGF(3, \"lwgeom_size_line returning %d\", result);\n\n\treturn result;\n}\n\nvoid printLWLINE(LWLINE *line)\n{\n\tlwnotice(\"LWLINE {\");\n\tlwnotice(\"    ndims = %i\", (int)TYPE_NDIMS(line->type));\n\tlwnotice(\"    SRID = %i\", (int)line->SRID);\n\tprintPA(line->points);\n\tlwnotice(\"}\");\n}\n\nint\nlwline_compute_box2d_p(LWLINE *line, BOX2DFLOAT4 *box)\n{\n\treturn ptarray_compute_box2d_p(line->points, box);\n}\n\n/* Clone LWLINE object. POINTARRAY is not copied. */\nLWLINE *\nlwline_clone(const LWLINE *g)\n{\n\tLWLINE *ret = lwalloc(sizeof(LWLINE));\n       \n\tLWDEBUGF(2, \"lwline_clone called with %p\", g);\n\n\tmemcpy(ret, g, sizeof(LWLINE));\n\tif ( g->bbox ) ret->bbox = box2d_clone(g->bbox);\n\treturn ret;\n}\n\n/*\n * Add 'what' to this line at position 'where'.\n * where=0 == prepend\n * where=-1 == append\n * Returns a MULTILINE or a GEOMETRYCOLLECTION\n */\nLWGEOM *\nlwline_add(const LWLINE *to, uint32 where, const LWGEOM *what)\n{\n\tLWCOLLECTION *col;\n\tLWGEOM **geoms;\n\tint newtype;\n\n\tif ( where != -1 && where != 0 )\n\t{\n\t\tlwerror(\"lwline_add only supports 0 or -1 as second argument, got %d\", where);\n\t\treturn NULL;\n\t}\n\n\t/* dimensions compatibility are checked by caller */\n\n\t/* Construct geoms array */\n\tgeoms = lwalloc(sizeof(LWGEOM *)*2);\n\tif ( where == -1 ) /* append */\n\t{\n\t\tgeoms[0] = lwgeom_clone((LWGEOM *)to);\n\t\tgeoms[1] = lwgeom_clone(what);\n\t}\n\telse /* prepend */\n\t{\n\t\tgeoms[0] = lwgeom_clone(what);\n\t\tgeoms[1] = lwgeom_clone((LWGEOM *)to);\n\t}\n\n\t/* reset SRID and wantbbox flag from component types */\n\tgeoms[0]->SRID = geoms[1]->SRID = -1;\n\tTYPE_SETHASSRID(geoms[0]->type, 0);\n\tTYPE_SETHASSRID(geoms[1]->type, 0);\n\tTYPE_SETHASBBOX(geoms[0]->type, 0);\n\tTYPE_SETHASBBOX(geoms[1]->type, 0);\n\n\t/* Find appropriate geom type */\n\tif ( TYPE_GETTYPE(what->type) == LINETYPE ) newtype = MULTILINETYPE;\n\telse newtype = COLLECTIONTYPE;\n\n\tcol = lwcollection_construct(newtype,\n\t\tto->SRID, NULL,\n\t\t2, geoms);\n\t\n\treturn (LWGEOM *)col;\n}\n\nvoid\nlwline_release(LWLINE *lwline)\n{\n  lwgeom_release(lwline_as_lwgeom(lwline));\n}\n\nvoid\nlwline_reverse(LWLINE *line)\n{\n\tptarray_reverse(line->points);\n}\n\nLWLINE *\nlwline_segmentize2d(LWLINE *line, double dist)\n{\n\treturn lwline_construct(line->SRID, NULL,\n\t\tptarray_segmentize2d(line->points, dist));\n}\n\n/* check coordinate equality  */\nchar\nlwline_same(const LWLINE *l1, const LWLINE *l2)\n{\n\treturn ptarray_same(l1->points, l2->points);\n}\n\n/*\n * Construct a LWLINE from an array of LWPOINTs\n * LWLINE dimensions are large enough to host all input dimensions.\n */\nLWLINE *\nlwline_from_lwpointarray(int SRID, unsigned int npoints, LWPOINT **points)\n{\n\tint zmflag=0;\n\tunsigned int i;\n\tPOINTARRAY *pa;\n\tuchar *newpoints, *ptr;\n\tsize_t ptsize, size;\n\n\t/*\n\t * Find output dimensions, check integrity\n\t */\n\tfor (i=0; i<npoints; i++)\n\t{\n\t\tif ( TYPE_GETTYPE(points[i]->type) != POINTTYPE )\n\t\t{\n\t\t\tlwerror(\"lwline_from_lwpointarray: invalid input type: %s\",\n\t\t\t\tlwgeom_typename(TYPE_GETTYPE(points[i]->type)));\n\t\t\treturn NULL;\n\t\t}\n\t\tif ( TYPE_HASZ(points[i]->type) ) zmflag |= 2;\n\t\tif ( TYPE_HASM(points[i]->type) ) zmflag |= 1;\n\t\tif ( zmflag == 3 ) break;\n\t}\n\n\tif ( zmflag == 0 ) ptsize=2*sizeof(double);\n\telse if ( zmflag == 3 ) ptsize=4*sizeof(double);\n\telse ptsize=3*sizeof(double);\n\n\t/*\n\t * Allocate output points array\n\t */\n\tsize = ptsize*npoints;\n\tnewpoints = lwalloc(size);\n\tmemset(newpoints, 0, size);\n\n\tptr=newpoints;\n\tfor (i=0; i<npoints; i++)\n\t{\n\t\tsize=pointArray_ptsize(points[i]->point);\n\t\tmemcpy(ptr, getPoint_internal(points[i]->point, 0), size);\n\t\tptr+=ptsize;\n\t}\n\n\tpa = pointArray_construct(newpoints, zmflag&2, zmflag&1, npoints);\n\n\treturn lwline_construct(SRID, NULL, pa);\n}\n\n/*\n * Construct a LWLINE from a LWMPOINT\n */\nLWLINE *\nlwline_from_lwmpoint(int SRID, LWMPOINT *mpoint)\n{\n\tunsigned int i;\n\tPOINTARRAY *pa;\n\tchar zmflag = TYPE_GETZM(mpoint->type);\n\tsize_t ptsize, size;\n\tuchar *newpoints, *ptr;\n\n\tif ( zmflag == 0 ) ptsize=2*sizeof(double);\n\telse if ( zmflag == 3 ) ptsize=4*sizeof(double);\n\telse ptsize=3*sizeof(double);\n\n\t/* Allocate space for output points */\n\tsize = ptsize*mpoint->ngeoms;\n\tnewpoints = lwalloc(size);\n\tmemset(newpoints, 0, size);\n\n\tptr=newpoints;\n\tfor (i=0; i<mpoint->ngeoms; i++)\n\t{\n\t\tmemcpy(ptr,\n\t\t\tgetPoint_internal(mpoint->geoms[i]->point, 0),\n\t\t\tptsize);\n\t\tptr+=ptsize;\n\t}\n\n\tpa = pointArray_construct(newpoints, zmflag&2, zmflag&1,\n\t\tmpoint->ngeoms);\n\n\tLWDEBUGF(3, \"lwline_from_lwmpoint: constructed pointarray for %d points, %d zmflag\", mpoint->ngeoms, zmflag);\n\n\treturn lwline_construct(SRID, NULL, pa);\n}\n\nLWLINE *\nlwline_addpoint(LWLINE *line, LWPOINT *point, unsigned int where)\n{\n\tPOINTARRAY *newpa;\n\tLWLINE *ret;\n\n\tnewpa = ptarray_addPoint(line->points,\n\t\tgetPoint_internal(point->point, 0),\n\t\tTYPE_NDIMS(point->type), where);\n\n\tret = lwline_construct(line->SRID, NULL, newpa);\n\n\treturn ret;\n}\n\nLWLINE *\nlwline_removepoint(LWLINE *line, unsigned int index)\n{\n\tPOINTARRAY *newpa;\n\tLWLINE *ret;\n\n\tnewpa = ptarray_removePoint(line->points, index);\n\n\tret = lwline_construct(line->SRID, NULL, newpa);\n\n\treturn ret;\n}\n\n/*\n * Note: input will be changed, make sure you have permissions for this.\n */\nvoid\nlwline_setPoint4d(LWLINE *line, unsigned int index, POINT4D *newpoint)\n{\n\tsetPoint4d(line->points, index, newpoint);\n}\n"
  },
  {
    "path": "src/liblwgeom/lwmcurve.c",
    "content": "/**********************************************************************\n * $Id: lwmcurve.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"liblwgeom.h\"\n\nLWMCURVE *\nlwmcurve_deserialize(uchar *srl)\n{\n        LWMCURVE *result;\n        LWGEOM_INSPECTED *insp;\n        int stype;\n        int type = lwgeom_getType(srl[0]);\n        int i;\n\n        if(type != MULTICURVETYPE)\n        {\n                lwerror(\"lwmcurve_deserialize called on NON multicurve: %d\", type);\n                return NULL;\n        }\n\n        insp = lwgeom_inspect(srl);\n\n        result = lwalloc(sizeof(LWMCURVE));\n        result->type = insp->type;\n        result->SRID = insp->SRID;\n        result->ngeoms = insp->ngeometries;\n        result->geoms = lwalloc(sizeof(LWGEOM *)*insp->ngeometries);\n\n        if(lwgeom_hasBBOX(srl[0]))\n        {\n                result->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n                memcpy(result->bbox, srl+1, sizeof(BOX2DFLOAT4));\n        }\n        else result->bbox = NULL;\n\n        for(i = 0; i < insp->ngeometries; i++)\n        {\n                stype = lwgeom_getType(insp->sub_geoms[i][0]);\n                if(stype == CIRCSTRINGTYPE)\n                {\n                        result->geoms[i] = (LWGEOM *)lwcircstring_deserialize(insp->sub_geoms[i]);\n                }\n                else if(stype == LINETYPE)\n                {\n                        result->geoms[i] = (LWGEOM *)lwline_deserialize(insp->sub_geoms[i]);\n                }\n                else\n                {\n                        lwerror(\"Only Circular and Line strings are currenly permitted in a MultiCurve.\");\n                        lwfree(result);\n                        lwfree(insp);\n                        return NULL;\n                }\n                        \n                if(TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type))\n                {\n                        lwerror(\"Mixed dimensions (multicurve: %d, curve %d:%d)\",\n                                TYPE_NDIMS(result->type), i,\n                                TYPE_NDIMS(result->geoms[i]->type));\n                        lwfree(result);\n                        lwfree(insp);\n                        return NULL;\n                }\n        }\n        return result;\n}\n\n/*\n * Add 'what' to this multicurve at position 'where'.\n * where=0 == prepend\n * where=-1 == append\n * Returns a MULTICURVE or a COLLECTION\n */\nLWGEOM *\nlwmcurve_add(const LWMCURVE *to, uint32 where, const LWGEOM *what)\n{\n        LWCOLLECTION *col;\n        LWGEOM **geoms;\n        int newtype;\n        uint32 i;\n\n        if(where == -1) where = to->ngeoms;\n        else if(where < -1 || where > to->ngeoms)\n        {\n                lwerror(\"lwmcurve_add: add position out of range %d..%d\",\n                        -1, to->ngeoms);\n                return NULL;\n        }\n\n        /* dimensions compatibility are checked by caller */\n\n        /* Construct geoms array */\n        geoms = lwalloc(sizeof(LWGEOM *)*(to->ngeoms+1));\n        for(i = 0; i < where; i++)\n        {\n                geoms[i] = lwgeom_clone((LWGEOM *)to->geoms[i]);\n        }\n        geoms[where] = lwgeom_clone(what);\n        for(i = where; i < to->ngeoms; i++) \n        {\n                geoms[i+1] = lwgeom_clone((LWGEOM *)to->geoms[i]);\n        }\n\n        if(TYPE_GETTYPE(what->type) == CIRCSTRINGTYPE) newtype = MULTICURVETYPE;\n        else newtype = COLLECTIONTYPE;\n\n        col = lwcollection_construct(newtype,\n                to->SRID, NULL,\n                to->ngeoms + 1, geoms);\n\n        return (LWGEOM *)col;\n}\n\n"
  },
  {
    "path": "src/liblwgeom/lwmline.c",
    "content": "/**********************************************************************\n * $Id: lwmline.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"liblwgeom.h\"\n\nvoid\nlwmline_release(LWMLINE *lwmline)\n{\n  lwgeom_release(lwmline_as_lwgeom(lwmline));\n}\n\nLWMLINE *\nlwmline_deserialize(uchar *srl)\n{\n\tLWMLINE *result;\n\tLWGEOM_INSPECTED *insp;\n\tint type = lwgeom_getType(srl[0]);\n\tint i;\n\n\tif ( type != MULTILINETYPE ) \n\t{\n\t\tlwerror(\"lwmline_deserialize called on NON multiline: %d\",\n\t\t\ttype);\n\t\treturn NULL;\n\t}\n\n\tinsp = lwgeom_inspect(srl);\n\n\tresult = lwalloc(sizeof(LWMLINE));\n\tresult->type = insp->type;\n\tresult->SRID = insp->SRID;\n\tresult->ngeoms = insp->ngeometries;\n\tresult->geoms = lwalloc(sizeof(LWLINE *)*insp->ngeometries);\n\n\tif (lwgeom_hasBBOX(srl[0]))\n\t{\n\t\tresult->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n\t\tmemcpy(result->bbox, srl+1, sizeof(BOX2DFLOAT4));\n\t}\n\telse result->bbox = NULL;\n\n\n\tfor (i=0; i<insp->ngeometries; i++)\n\t{\n\t\tresult->geoms[i] = lwline_deserialize(insp->sub_geoms[i]);\n\t\tif ( TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type) )\n\t\t{\n\t\t\tlwerror(\"Mixed dimensions (multiline:%d, line%d:%d)\",\n\t\t\t\tTYPE_NDIMS(result->type), i,\n\t\t\t\tTYPE_NDIMS(result->geoms[i]->type)\n\t\t\t);\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/*\n * Add 'what' to this multiline at position 'where'.\n * where=0 == prepend\n * where=-1 == append\n * Returns a MULTILINE or a COLLECTION\n */\nLWGEOM *\nlwmline_add(const LWMLINE *to, uint32 where, const LWGEOM *what)\n{\n\tLWCOLLECTION *col;\n\tLWGEOM **geoms;\n\tint newtype;\n\tuint32 i;\n\n\tif ( where == -1 ) where = to->ngeoms;\n\telse if ( where < -1 || where > to->ngeoms )\n\t{\n\t\tlwerror(\"lwmline_add: add position out of range %d..%d\",\n\t\t\t-1, to->ngeoms);\n\t\treturn NULL;\n\t}\n\n\t/* dimensions compatibility are checked by caller */\n\n\t/* Construct geoms array */\n\tgeoms = lwalloc(sizeof(LWGEOM *)*(to->ngeoms+1));\n\tfor (i=0; i<where; i++)\n\t{\n\t\tgeoms[i] = lwgeom_clone((LWGEOM *)to->geoms[i]);\n\t}\n\tgeoms[where] = lwgeom_clone(what);\n\tfor (i=where; i<to->ngeoms; i++)\n\t{\n\t\tgeoms[i+1] = lwgeom_clone((LWGEOM *)to->geoms[i]);\n\t}\n\n\tif ( TYPE_GETTYPE(what->type) == LINETYPE ) newtype = MULTILINETYPE;\n\telse newtype = COLLECTIONTYPE;\n\n\tcol = lwcollection_construct(newtype,\n\t\tto->SRID, NULL,\n\t\tto->ngeoms+1, geoms);\n\t\n\treturn (LWGEOM *)col;\n\n}\n\nvoid lwmline_free(LWMLINE *mline) \n{\n\tint i;\n\tif( mline->bbox ) \n\t{\n\t\tlwfree(mline->bbox);\n\t}\n\tfor ( i = 0; i < mline->ngeoms; i++ ) \n\t{\n\t\tif( mline->geoms[i] ) {\n\t\t\tlwline_free(mline->geoms[i]);\n\t\t}\n\t}\n\tif( mline->geoms ) \n\t{\n\t\tlwfree(mline->geoms);\n\t}\n\tlwfree(mline);\n\t\n};\n"
  },
  {
    "path": "src/liblwgeom/lwmpoint.c",
    "content": "/**********************************************************************\n * $Id: lwmpoint.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"liblwgeom.h\"\n\nvoid\nlwmpoint_release(LWMPOINT *lwmpoint)\n{\n  lwgeom_release(lwmpoint_as_lwgeom(lwmpoint));\n}\n\n\nLWMPOINT *\nlwmpoint_deserialize(uchar *srl)\n{\n\tLWMPOINT *result;\n\tLWGEOM_INSPECTED *insp;\n\tint type = lwgeom_getType(srl[0]);\n\tint i;\n\n\tif ( type != MULTIPOINTTYPE ) \n\t{\n\t\tlwerror(\"lwmpoint_deserialize called on NON multipoint: %d\",\n\t\t\ttype);\n\t\treturn NULL;\n\t}\n\n\tinsp = lwgeom_inspect(srl);\n\n\tresult = lwalloc(sizeof(LWMPOINT));\n\tresult->type = insp->type;\n\tresult->SRID = insp->SRID;\n\tresult->ngeoms = insp->ngeometries;\n\tresult->geoms = lwalloc(sizeof(LWPOINT *)*result->ngeoms);\n\n\tif (lwgeom_hasBBOX(srl[0]))\n\t{\n\t\tresult->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n\t\tmemcpy(result->bbox, srl+1, sizeof(BOX2DFLOAT4));\n\t}\n\telse result->bbox = NULL;\n\n\tfor (i=0; i<insp->ngeometries; i++)\n\t{\n\t\tresult->geoms[i] = lwpoint_deserialize(insp->sub_geoms[i]);\n\t\tif ( TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type) )\n\t\t{\n\t\t\tlwerror(\"Mixed dimensions (multipoint:%d, point%d:%d)\",\n\t\t\t\tTYPE_NDIMS(result->type), i,\n\t\t\t\tTYPE_NDIMS(result->geoms[i]->type)\n\t\t\t);\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/*\n * Add 'what' to this multipoint at position 'where'.\n * where=0 == prepend\n * where=-1 == append\n * Returns a MULTIPOINT or a COLLECTION\n */\nLWGEOM *\nlwmpoint_add(const LWMPOINT *to, uint32 where, const LWGEOM *what)\n{\n\tLWCOLLECTION *col;\n\tLWGEOM **geoms;\n\tint newtype;\n\tuint32 i;\n\n\tif ( where == -1 ) where = to->ngeoms;\n\telse if ( where < -1 || where > to->ngeoms )\n\t{\n\t\tlwerror(\"lwmpoint_add: add position out of range %d..%d\",\n\t\t\t-1, to->ngeoms);\n\t\treturn NULL;\n\t}\n\n\t/* dimensions compatibility are checked by caller */\n\n\t/* Construct geoms array */\n\tgeoms = lwalloc(sizeof(LWGEOM *)*(to->ngeoms+1));\n\tfor (i=0; i<where; i++)\n\t{\n\t\tgeoms[i] = lwgeom_clone((LWGEOM *)to->geoms[i]);\n\t}\n\tgeoms[where] = lwgeom_clone(what);\n\tfor (i=where; i<to->ngeoms; i++)\n\t{\n\t\tgeoms[i+1] = lwgeom_clone((LWGEOM *)to->geoms[i]);\n\t}\n\n\tif ( TYPE_GETTYPE(what->type) == POINTTYPE ) newtype = MULTIPOINTTYPE;\n\telse newtype = COLLECTIONTYPE;\n\n\tcol = lwcollection_construct(newtype,\n\t\tto->SRID, NULL,\n\t\tto->ngeoms+1, geoms);\n\t\n\treturn (LWGEOM *)col;\n\n}\n\nvoid lwmpoint_free(LWMPOINT *mpt) \n{\n\tint i;\n\tif( mpt->bbox ) \n\t{\n\t\tlwfree(mpt->bbox);\n\t}\n\tfor ( i = 0; i < mpt->ngeoms; i++ ) \n\t{\n\t\tif( mpt->geoms[i] ) {\n\t\t\tlwpoint_free(mpt->geoms[i]);\n\t\t}\n\t}\n\tif( mpt->geoms ) \n\t{\n\t\tlwfree(mpt->geoms);\n\t}\n\tlwfree(mpt);\n\t\n};\n\n"
  },
  {
    "path": "src/liblwgeom/lwmpoly.c",
    "content": "/**********************************************************************\n * $Id: lwmpoly.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"liblwgeom.h\"\n\n\nvoid\nlwmpoly_release(LWMPOLY *lwmpoly)\n{\n  lwgeom_release(lwmpoly_as_lwgeom(lwmpoly));\n}\n\n\nLWMPOLY *\nlwmpoly_deserialize(uchar *srl)\n{\n\tLWMPOLY *result;\n\tLWGEOM_INSPECTED *insp;\n\tint type = lwgeom_getType(srl[0]);\n\tint i;\n\n\tLWDEBUG(2, \"lwmpoly_deserialize called\");\n\n\tif ( type != MULTIPOLYGONTYPE ) \n\t{\n\t\tlwerror(\"lwmpoly_deserialize called on NON multipoly: %d\",\n\t\t\ttype);\n\t\treturn NULL;\n\t}\n\n\tinsp = lwgeom_inspect(srl);\n\n\tresult = lwalloc(sizeof(LWMPOLY));\n\tresult->type = insp->type;\n\tresult->SRID = insp->SRID;\n\tresult->ngeoms = insp->ngeometries;\n\tresult->geoms = lwalloc(sizeof(LWPOLY *)*insp->ngeometries);\n\n\tif (lwgeom_hasBBOX(srl[0]))\n\t{\n\t\tresult->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n\t\tmemcpy(result->bbox, srl+1, sizeof(BOX2DFLOAT4));\n\t}\n\telse result->bbox = NULL;\n\n\tfor (i=0; i<insp->ngeometries; i++)\n\t{\n\t\tresult->geoms[i] = lwpoly_deserialize(insp->sub_geoms[i]);\n\t\tif ( TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type) )\n\t\t{\n\t\t\tlwerror(\"Mixed dimensions (multipoly:%d, poly%d:%d)\",\n\t\t\t\tTYPE_NDIMS(result->type), i,\n\t\t\t\tTYPE_NDIMS(result->geoms[i]->type)\n\t\t\t);\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/*\n * Add 'what' to this multiline at position 'where'.\n * where=0 == prepend\n * where=-1 == append\n * Returns a MULTIPOLY or a COLLECTION\n */\nLWGEOM *\nlwmpoly_add(const LWMPOLY *to, uint32 where, const LWGEOM *what)\n{\n\tLWCOLLECTION *col;\n\tLWGEOM **geoms;\n\tint newtype;\n\tuint32 i;\n\n\tif ( where == -1 ) where = to->ngeoms;\n\telse if ( where < -1 || where > to->ngeoms )\n\t{\n\t\tlwerror(\"lwmline_add: add position out of range %d..%d\",\n\t\t\t-1, to->ngeoms);\n\t\treturn NULL;\n\t}\n\n\t/* dimensions compatibility are checked by caller */\n\n\t/* Construct geoms array */\n\tgeoms = lwalloc(sizeof(LWGEOM *)*(to->ngeoms+1));\n\tfor (i=0; i<where; i++)\n\t{\n\t\tgeoms[i] = lwgeom_clone((LWGEOM *)to->geoms[i]);\n\t}\n\tgeoms[where] = lwgeom_clone(what);\n\tfor (i=where; i<to->ngeoms; i++)\n\t{\n\t\tgeoms[i+1] = lwgeom_clone((LWGEOM *)to->geoms[i]);\n\t}\n\n\tif ( TYPE_GETTYPE(what->type) == POLYGONTYPE ) newtype = MULTIPOLYGONTYPE;\n\telse newtype = COLLECTIONTYPE;\n\n\tcol = lwcollection_construct(newtype,\n\t\tto->SRID, NULL,\n\t\tto->ngeoms+1, geoms);\n\t\n\treturn (LWGEOM *)col;\n\n}\n\nvoid lwmpoly_free(LWMPOLY *mpoly) \n{\n\tint i;\n\tif( mpoly->bbox ) \n\t{\n\t\tlwfree(mpoly->bbox);\n\t}\n\tfor ( i = 0; i < mpoly->ngeoms; i++ ) \n\t{\n\t\tif( mpoly->geoms[i] ) {\n\t\t\tlwpoly_free(mpoly->geoms[i]);\n\t\t}\n\t}\n\tif( mpoly->geoms ) \n\t{\n\t\tlwfree(mpoly->geoms);\n\t}\n\tlwfree(mpoly);\n\t\n};\n\n"
  },
  {
    "path": "src/liblwgeom/lwmsurface.c",
    "content": "/**********************************************************************\n * $Id: lwmsurface.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"liblwgeom.h\"\n\n\nLWMSURFACE *\nlwmsurface_deserialize(uchar *srl)\n{\n        LWMSURFACE *result;\n        LWGEOM_INSPECTED *insp;\n        int stype;\n        int type = lwgeom_getType(srl[0]);\n        int i;\n\n        LWDEBUG(2, \"lwmsurface_deserialize called\");\n\n        if(type != MULTISURFACETYPE)\n        {\n                lwerror(\"lwmsurface_deserialize called on a non-multisurface: %d\", type);\n                return NULL;\n        }\n\n        insp = lwgeom_inspect(srl);\n\n        result = lwalloc(sizeof(LWMSURFACE));\n        result->type = insp->type;\n        result->SRID = insp->SRID;\n        result->ngeoms = insp->ngeometries;\n        result->geoms = lwalloc(sizeof(LWPOLY *)*insp->ngeometries);\n\n        if(lwgeom_hasBBOX(srl[0]))\n        {\n                result->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n                memcpy(result->bbox, srl + 1, sizeof(BOX2DFLOAT4));\n        }\n        else result->bbox = NULL;\n\n        for(i = 0; i < insp->ngeometries; i++)\n        {\n                stype = lwgeom_getType(insp->sub_geoms[i][0]);\n                if(stype == POLYGONTYPE) \n                {\n                        result->geoms[i] = (LWGEOM *)lwpoly_deserialize(insp->sub_geoms[i]);\n                }\n                else if(stype == CURVEPOLYTYPE)\n                {\n                        result->geoms[i] = (LWGEOM *)lwcurvepoly_deserialize(insp->sub_geoms[i]);\n                }\n                else\n                {\n                        lwerror(\"Only Polygons and Curved Polygons are supported in a MultiSurface.\");\n                        lwfree(result);\n                        lwfree(insp);\n                        return NULL;\n                }\n\n                if(TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type))\n                {\n                        lwerror(\"Mixed dimensions (multisurface: %d, surface %d:%d\", \n                                TYPE_NDIMS(result->type), i, \n                                TYPE_NDIMS(result->geoms[i]->type));\n                        lwfree(result);\n                        lwfree(insp);\n                        return NULL;\n                }\n        }\n        return result;\n}\n\n/*\n * Add 'what' to this multisurface at position 'where'\n * where=0 == prepend\n * where=-1 == append\n * Returns a MULTISURFACE or a COLLECTION\n */\nLWGEOM *\nlwmsurface_add(const LWMSURFACE *to, uint32 where, const LWGEOM *what)\n{\n        LWCOLLECTION *col;\n        LWGEOM **geoms;\n        int newtype;\n        uint32 i;\n        \n        if(where == -1) where = to->ngeoms;\n        else if(where < -1 || where > to->ngeoms)\n        {\n                lwerror(\"lwmsurface_add: add position out of range %d..%d\",\n                        -1, to->ngeoms);\n                return NULL;\n        }\n\n        /* dimensions compatibility are checked by caller */\n\n        /* Construct geoms array */\n        geoms = lwalloc(sizeof(LWGEOM *)*(to->ngeoms+1));\n        for(i = 0; i < where; i++)\n        {\n                geoms[i] = lwgeom_clone((LWGEOM *)to->geoms[i]);\n        }\n        geoms[where] = lwgeom_clone(what);\n        for(i = where; i < to->ngeoms; i++)\n        {\n                geoms[i+1] = lwgeom_clone((LWGEOM *)to->geoms[i]);\n        }\n\n        if(TYPE_GETTYPE(what->type) == POLYGONTYPE \n                || TYPE_GETTYPE(what->type) == CURVEPOLYTYPE) \n            newtype = MULTISURFACETYPE;\n        else newtype = COLLECTIONTYPE;\n\n        col = lwcollection_construct(newtype,\n            to->SRID, NULL, to->ngeoms + 1, geoms);\n\n        return (LWGEOM *)col;\n}\n\n"
  },
  {
    "path": "src/liblwgeom/lwpoint.c",
    "content": "/**********************************************************************\n * $Id: lwpoint.c 3812 2009-03-09 14:36:15Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"liblwgeom.h\"\n\n\n/*\n * Convert this point into its serialize form\n * result's first char will be the 8bit type.  See serialized form doc\n */\nuchar *\nlwpoint_serialize(LWPOINT *point)\n{\n\tsize_t size, retsize;\n\tuchar *result;\n\n\tsize = lwpoint_serialize_size(point);\n\tresult = lwalloc(size);\n\tlwpoint_serialize_buf(point, result, &retsize);\n\n\tif ( retsize != size )\n\t{\n\t\tlwerror(\"lwpoint_serialize_size returned %d, ..serialize_buf returned %d\", size, retsize);\n\t}\n\n\treturn result;\n}\n\n/*\n * Convert this point into its serialize form writing it into\n * the given buffer, and returning number of bytes written into\n * the given int pointer.\n * result's first char will be the 8bit type.  See serialized form doc\n */\nvoid\nlwpoint_serialize_buf(LWPOINT *point, uchar *buf, size_t *retsize)\n{\n\tint size=1;\n\tchar hasSRID;\n\tuchar *loc;\n\tint ptsize = pointArray_ptsize(point->point);\n\n\tif ( TYPE_GETZM(point->type) != TYPE_GETZM(point->point->dims) )\n\t\tlwerror(\"Dimensions mismatch in lwpoint\");\n\n\tLWDEBUGF(2, \"lwpoint_serialize_buf(%p, %p) called\", point, buf);\n\t/*printLWPOINT(point); */\n\n\thasSRID = (point->SRID != -1);\n\n\tif (hasSRID) size +=4;  /*4 byte SRID */\n\tif (point->bbox) size += sizeof(BOX2DFLOAT4); /* bvol */\n\n\tsize += sizeof(double)*TYPE_NDIMS(point->type);\n\n\tbuf[0] = (uchar) lwgeom_makeType_full(\n\t\tTYPE_HASZ(point->type), TYPE_HASM(point->type),\n\t\thasSRID, POINTTYPE, point->bbox?1:0);\n\tloc = buf+1;\n\n\tif (point->bbox)\n\t{\n\t\tmemcpy(loc, point->bbox, sizeof(BOX2DFLOAT4));\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t}\n\n\tif (hasSRID)\n\t{\n\t\tmemcpy(loc, &point->SRID, sizeof(int32));\n\t\tloc += 4;\n\t}\n\n\t/* copy in points */\n\tmemcpy(loc, getPoint_internal(point->point, 0), ptsize);\n\n\tif (retsize) *retsize = size;\n}\n\n/*\n * Find bounding box (standard one) \n *   zmin=zmax=NO_Z_VALUE if 2d \n */\nBOX3D *\nlwpoint_compute_box3d(LWPOINT *point)\n{\n\tLWDEBUGF(2, \"lwpoint_compute_box3d called with point %p\", point);\n\n\tif (point == NULL)\n\t{\n\t\tLWDEBUG(3, \"lwpoint_compute_box3d returning NULL\");\n\n\t\treturn NULL;\n\t}\n\n\tLWDEBUG(3, \"lwpoint_compute_box3d returning ptarray_compute_box3d return\");\n\n\treturn ptarray_compute_box3d(point->point);\n}\n\n/*\n * Convenience functions to hide the POINTARRAY\n * TODO: obsolete this\n */\nint\nlwpoint_getPoint2d_p(const LWPOINT *point, POINT2D *out)\n{\n\treturn getPoint2d_p(point->point, 0, out);\n}\n\n/* convenience functions to hide the POINTARRAY */\nint\nlwpoint_getPoint3dz_p(const LWPOINT *point, POINT3DZ *out)\n{\n\treturn getPoint3dz_p(point->point,0,out);\n}\nint\nlwpoint_getPoint3dm_p(const LWPOINT *point, POINT3DM *out)\n{\n\treturn getPoint3dm_p(point->point,0,out);\n}\nint\nlwpoint_getPoint4d_p(const LWPOINT *point, POINT4D *out)\n{\n\treturn getPoint4d_p(point->point,0,out);\n}\n\n/* find length of this deserialized point */\nsize_t\nlwpoint_serialize_size(LWPOINT *point)\n{\n\tsize_t size = 1; /* type */\n\n\tLWDEBUG(2, \"lwpoint_serialize_size called\");\n\n\tif ( point->SRID != -1 ) size += 4; /* SRID */\n\tif ( point->bbox ) size += sizeof(BOX2DFLOAT4);\n\n\tsize += TYPE_NDIMS(point->type) * sizeof(double); /* point */\n\n\tLWDEBUGF(3, \"lwpoint_serialize_size returning %d\", size);\n\n\treturn size; \n}\n\n/*\n * Construct a new point.  point will not be copied\n * use SRID=-1 for unknown SRID (will have 8bit type's S = 0)\n */\nLWPOINT *\nlwpoint_construct(int SRID, BOX2DFLOAT4 *bbox, POINTARRAY *point)\n{\n\tLWPOINT *result ;\n\n\tif (point == NULL)\n\t\treturn NULL; /* error */\n\n\tresult = lwalloc(sizeof(LWPOINT));\n\tresult->type = lwgeom_makeType_full(TYPE_HASZ(point->dims), TYPE_HASM(point->dims), (SRID!=-1), POINTTYPE, 0);\n\tresult->SRID = SRID;\n\tresult->point = point;\n\tresult->bbox = bbox;\n\n\treturn result;\n}\n\nLWPOINT *\nmake_lwpoint2d(int SRID, double x, double y)\n{\n\tPOINT2D p;\n\tPOINTARRAY *pa = ptarray_construct(0, 0, 1);\n\n\tp.x = x;\n\tp.y = y;\n\n\tmemcpy(getPoint_internal(pa, 0), &p, sizeof(POINT2D));\n\n\treturn lwpoint_construct(SRID, NULL, pa);\n}\n\nLWPOINT *\nmake_lwpoint3dz(int SRID, double x, double y, double z)\n{\n\tPOINT3DZ p;\n\tPOINTARRAY *pa = ptarray_construct(1, 0, 1);\n\n\tp.x = x;\n\tp.y = y;\n\tp.z = z;\n\n\tmemcpy(getPoint_internal(pa, 0), &p, sizeof(POINT3DZ));\n\n\treturn lwpoint_construct(SRID, NULL, pa);\n}\n\nLWPOINT *\nmake_lwpoint3dm(int SRID, double x, double y, double m)\n{\n\tPOINTARRAY *pa = ptarray_construct(0, 1, 1);\n\tPOINT3DM p;\n\n\tp.x = x;\n\tp.y = y;\n\tp.m = m;\n\n\tmemcpy(getPoint_internal(pa, 0), &p, sizeof(POINT3DM));\n\n\treturn lwpoint_construct(SRID, NULL, pa);\n}\n\nLWPOINT *\nmake_lwpoint4d(int SRID, double x, double y, double z, double m)\n{\n\tPOINTARRAY *pa = ptarray_construct(1, 1, 1);\n\tPOINT4D p;\n\t\n\tp.x = x;\n\tp.y = y;\n\tp.z = z;\n\tp.m = m;\n\n\tmemcpy(getPoint_internal(pa, 0), &p, sizeof(POINT4D));\n\n\treturn lwpoint_construct(SRID, NULL, pa);\n}\n\n/*\n * Given the LWPOINT serialized form (or a pointer into a muli* one)\n * construct a proper LWPOINT.\n * serialized_form should point to the 8bit type format (with type = 1)\n * See serialized form doc\n */\nLWPOINT *\nlwpoint_deserialize(uchar *serialized_form)\n{\n\tuchar type;\n\tint geom_type;\n\tLWPOINT *result;\n\tuchar *loc = NULL;\n\tPOINTARRAY *pa;\n\n\tLWDEBUG(2, \"lwpoint_deserialize called\");\n\n\tresult = (LWPOINT*) lwalloc(sizeof(LWPOINT)) ;\n\n\ttype = serialized_form[0];\n\tgeom_type = lwgeom_getType(type);\n\n\tif ( geom_type != POINTTYPE)\n\t{\n\t\tlwerror(\"lwpoint_deserialize: attempt to deserialize a point which is really a %s\", lwgeom_typename(geom_type));\n\t\treturn NULL;\n\t}\n\tresult->type = type;\n\n\tloc = serialized_form+1;\n\n\tif (lwgeom_hasBBOX(type))\n\t{\n\t\tLWDEBUG(3, \"lwpoint_deserialize: input has bbox\");\n\n\t\tresult->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n\t\tmemcpy(result->bbox, loc, sizeof(BOX2DFLOAT4));\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t}\n\telse\n\t{\n\t\tresult->bbox = NULL;\n\t}\n\n\tif ( lwgeom_hasSRID(type))\n\t{\n\t\tLWDEBUG(3, \"lwpoint_deserialize: input has SRID\");\n\n\t\tresult->SRID = lw_get_int32(loc);\n\t\tloc += 4; /* type + SRID */\n\t}\n\telse\n\t{\n\t\tresult->SRID = -1;\n\t}\n\n\t/* we've read the type (1 byte) and SRID (4 bytes, if present) */\n\n\tpa = pointArray_construct(loc, TYPE_HASZ(type), TYPE_HASM(type), 1);\n\n\tresult->point = pa;\n\n\treturn result;\n}\n\nvoid lwpoint_free(LWPOINT *pt)\n{\n\tif(pt->point)\n\t\tptarray_free(pt->point);\n\tlwfree(pt);\n}\n\nvoid printLWPOINT(LWPOINT *point)\n{\n\tlwnotice(\"LWPOINT {\");\n\tlwnotice(\"    ndims = %i\", (int)TYPE_NDIMS(point->type));\n\tlwnotice(\"    BBOX = %i\", TYPE_HASBBOX(point->type) ? 1 : 0 );\n\tlwnotice(\"    SRID = %i\", (int)point->SRID);\n\tprintPA(point->point);\n\tlwnotice(\"}\");\n}\n\nint\nlwpoint_compute_box2d_p(LWPOINT *point, BOX2DFLOAT4 *box)\n{\n\treturn ptarray_compute_box2d_p(point->point, box);\n}\n\n/* Clone LWPOINT object. POINTARRAY is not copied. */\nLWPOINT *\nlwpoint_clone(const LWPOINT *g)\n{\n\tLWPOINT *ret = lwalloc(sizeof(LWPOINT));\n\n\tLWDEBUG(2, \"lwpoint_clone called\");\n\n\tmemcpy(ret, g, sizeof(LWPOINT));\n\tif ( g->bbox ) ret->bbox = box2d_clone(g->bbox);\n\treturn ret;\n}\n\n/*\n * Add 'what' to this point at position 'where'.\n * where=0 == prepend\n * where=-1 == append\n * Returns a MULTIPOINT or a GEOMETRYCOLLECTION\n */\nLWGEOM *\nlwpoint_add(const LWPOINT *to, uint32 where, const LWGEOM *what)\n{\n\tLWCOLLECTION *col;\n\tLWGEOM **geoms;\n\tint newtype;\n\n\tif ( where != -1 && where != 0 )\n\t{\n\t\tlwerror(\"lwpoint_add only supports 0 or -1 as second argument, got %d\", where);\n\t\treturn NULL;\n\t}\n\n\t/* dimensions compatibility are checked by caller */\n\n\n\t/* Construct geoms array */\n\tgeoms = lwalloc(sizeof(LWGEOM *)*2);\n\tif ( where == -1 ) /* append */\n\t{\n\t\tgeoms[0] = lwgeom_clone((LWGEOM *)to);\n\t\tgeoms[1] = lwgeom_clone(what);\n\t}\n\telse /* prepend */\n\t{\n\t\tgeoms[0] = lwgeom_clone(what);\n\t\tgeoms[1] = lwgeom_clone((LWGEOM *)to);\n\t}\n\t/* reset SRID and wantbbox flag from component types */\n\tlwgeom_dropSRID(geoms[0]);\n\tlwgeom_drop_bbox(geoms[0]);\n\tlwgeom_dropSRID(geoms[1]);\n\tlwgeom_drop_bbox(geoms[1]);\n\n\t/* Find appropriate geom type */\n\tif ( TYPE_GETTYPE(what->type) == POINTTYPE ) newtype = MULTIPOINTTYPE;\n\telse newtype = COLLECTIONTYPE;\n\n\tcol = lwcollection_construct(newtype,\n\t\tto->SRID, NULL,\n\t\t2, geoms);\n\t\n\treturn (LWGEOM *)col;\n}\n\n/* Find length of this serialized point */\nsize_t\nlwgeom_size_point(const uchar *serialized_point)\n{\n\tuint32  result = 1;\n\tuchar type;\n\tconst uchar *loc;\n\n\ttype = serialized_point[0];\n\n\tif ( lwgeom_getType(type) != POINTTYPE) return 0;\n\n\tLWDEBUGF(2, \"lwgeom_size_point called (%d)\", result);\n\n\tloc = serialized_point+1;\n\n\tif (lwgeom_hasBBOX(type))\n\t{\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t\tresult +=sizeof(BOX2DFLOAT4);\n\n\t\tLWDEBUGF(3, \"lwgeom_size_point: has bbox (%d)\", result);\n\t}\n\n\tif ( lwgeom_hasSRID(type))\n\t{\n\t\tLWDEBUGF(3, \"lwgeom_size_point: has srid (%d)\", result);\n\n\t\tloc +=4; /* type + SRID */\n\t\tresult +=4;\n\t}\n\n\tresult += lwgeom_ndims(type)*sizeof(double);\n\n\treturn result;\n}\n\nvoid\nlwpoint_release(LWPOINT *lwpoint)\n{\n  lwgeom_release(lwpoint_as_lwgeom(lwpoint));\n}\n\n\n/* check coordinate equality  */\nchar\nlwpoint_same(const LWPOINT *p1, const LWPOINT *p2)\n{\n\treturn ptarray_same(p1->point, p2->point);\n}\n"
  },
  {
    "path": "src/liblwgeom/lwpoly.c",
    "content": "/**********************************************************************\n * $Id: lwpoly.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n/* basic LWPOLY manipulation */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"liblwgeom.h\"\n\n\n#define CHECK_POLY_RINGS_ZM 1\n\n/* construct a new LWPOLY.  arrays (points/points per ring) will NOT be copied\n * use SRID=-1 for unknown SRID (will have 8bit type's S = 0)\n */\nLWPOLY *\nlwpoly_construct(int SRID, BOX2DFLOAT4 *bbox, unsigned int nrings, POINTARRAY **points)\n{\n\tLWPOLY *result;\n\tint hasz, hasm;\n#ifdef CHECK_POLY_RINGS_ZM\n\tchar zm;\n\tunsigned int i;\n#endif\n\n\tif ( nrings < 1 ) lwerror(\"lwpoly_construct: need at least 1 ring\");\n\n\thasz = TYPE_HASZ(points[0]->dims);\n\thasm = TYPE_HASM(points[0]->dims);\n\n#ifdef CHECK_POLY_RINGS_ZM\n\tzm = TYPE_GETZM(points[0]->dims);\n\tfor (i=1; i<nrings; i++)\n\t{\n\t\tif ( zm != TYPE_GETZM(points[i]->dims) )\n\t\t\tlwerror(\"lwpoly_construct: mixed dimensioned rings\");\n\t}\n#endif\n\n\tresult = (LWPOLY*) lwalloc(sizeof(LWPOLY));\n\tresult->type = lwgeom_makeType_full(hasz, hasm, (SRID!=-1), POLYGONTYPE,\n\t\t0);\n\tresult->SRID = SRID;\n\tresult->nrings = nrings;\n\tresult->rings = points;\n\tresult->bbox = bbox;\n\n\treturn result;\n}\n\n\n/*\n * given the LWPOLY serialized form (or a pointer into a muli* one)\n * construct a proper LWPOLY.\n * serialized_form should point to the 8bit type format (with type = 3)\n * See serialized form doc\n */\nLWPOLY *\nlwpoly_deserialize(uchar *serialized_form)\n{\n\n\tLWPOLY *result;\n\tuint32 nrings;\n\tint ndims, hasz, hasm;\n\tuint32 npoints;\n\tuchar type;\n\tuchar *loc;\n\tint t;\n\n\tif (serialized_form == NULL)\n\t{\n\t\tlwerror(\"lwpoly_deserialize called with NULL arg\");\n\t\treturn NULL;\n\t}\n\n\tresult = (LWPOLY*) lwalloc(sizeof(LWPOLY));\n\n\ttype = serialized_form[0];\n\tresult->type = type;\n\n\tndims = TYPE_NDIMS(type);\n\thasz = TYPE_HASZ(type);\n\thasm = TYPE_HASM(type);\n\tloc = serialized_form;\n\n\tif ( TYPE_GETTYPE(type) != POLYGONTYPE)\n\t{\n\t\tlwerror(\"lwpoly_deserialize: attempt to deserialize a poly which is really a %s\", lwgeom_typename(type));\n\t\treturn NULL;\n\t}\n\n\n\tloc = serialized_form+1;\n\n\tif (lwgeom_hasBBOX(type)) {\n\t\tLWDEBUG(3, \"lwpoly_deserialize: input has bbox\");\n\n\t\tresult->bbox = lwalloc(sizeof(BOX2DFLOAT4));\n\t\tmemcpy(result->bbox, loc, sizeof(BOX2DFLOAT4));\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t} else {\n\t\tresult->bbox = NULL;\n\t}\n\n\tif ( lwgeom_hasSRID(type))\n\t{\n\t\tresult->SRID = lw_get_int32(loc);\n\t\tloc +=4; /* type + SRID */\n\t}\n\telse\n\t{\n\t\tresult->SRID = -1;\n\t}\n\n\tnrings = lw_get_uint32(loc);\n\tresult->nrings = nrings;\n\tloc +=4;\n\tresult->rings = (POINTARRAY**) lwalloc(nrings* sizeof(POINTARRAY*));\n\n\tfor (t =0;t<nrings;t++)\n\t{\n\t\t/* read in a single ring and make a PA */\n\t\tnpoints = lw_get_uint32(loc);\n\t\tloc +=4;\n\n\t\tresult->rings[t] = pointArray_construct(loc, hasz, hasm, npoints);\n\t\tloc += sizeof(double)*ndims*npoints;\n\t}\n\n\treturn result;\n}\n\n/*\n * create the serialized form of the polygon\n * result's first char will be the 8bit type.  See serialized form doc\n * points copied\n */\nuchar *\nlwpoly_serialize(LWPOLY *poly)\n{\n\tsize_t size, retsize;\n\tuchar *result;\n\n\tsize = lwpoly_serialize_size(poly);\n\tresult = lwalloc(size);\n\tlwpoly_serialize_buf(poly, result, &retsize);\n\t\n\tif ( retsize != size )\n\t{\n\t\tlwerror(\"lwpoly_serialize_size returned %d, ..serialize_buf returned %d\", size, retsize);\n\t}\n\n\treturn result;\n}\n\n/*\n * create the serialized form of the polygon writing it into the\n * given buffer, and returning number of bytes written into\n * the given int pointer.\n * result's first char will be the 8bit type.  See serialized form doc\n * points copied\n */\nvoid\nlwpoly_serialize_buf(LWPOLY *poly, uchar *buf, size_t *retsize)\n{\n\tsize_t size=1;  /* type byte */\n\tchar hasSRID;\n\tint t;\n\tuchar *loc;\n\tint ptsize;\n\n\tLWDEBUG(2, \"lwpoly_serialize_buf called\");\n\n\tptsize = sizeof(double)*TYPE_NDIMS(poly->type);\n\n\thasSRID = (poly->SRID != -1);\n\n\tsize += 4; /* nrings */\n\tsize += 4*poly->nrings; /* npoints/ring */\n\n\tbuf[0] = (uchar) lwgeom_makeType_full(\n\t\tTYPE_HASZ(poly->type), TYPE_HASM(poly->type),\n\t\thasSRID, POLYGONTYPE, poly->bbox ? 1 : 0);\n\tloc = buf+1;\n\n\tif (poly->bbox)\n\t{\n\t\tmemcpy(loc, poly->bbox, sizeof(BOX2DFLOAT4));\n\t\tsize += sizeof(BOX2DFLOAT4); /* bvol */\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t}\n\n\tif (hasSRID)\n\t{\n\t\tmemcpy(loc, &poly->SRID, sizeof(int32));\n\t\tloc += 4;\n\t\tsize +=4;  /* 4 byte SRID */\n\t}\n\n\tmemcpy(loc, &poly->nrings, sizeof(int32));  /* nrings */\n\tloc+=4;\n\n\tfor (t=0;t<poly->nrings;t++)\n\t{\n\t\tPOINTARRAY *pa = poly->rings[t];\n\t\tsize_t pasize;\n\t\tuint32 npoints;\n\n\t\tif ( TYPE_GETZM(poly->type) != TYPE_GETZM(pa->dims) )\n\t\t\tlwerror(\"Dimensions mismatch in lwpoly\");\n\n\t\tnpoints = pa->npoints;\n\n\t\tmemcpy(loc, &npoints, sizeof(uint32)); /* npoints this ring */\n\t\tloc+=4;\n\n\t\tpasize = npoints*ptsize;\n\t\tsize += pasize;\n\n\t\t/* copy points */\n\t\tmemcpy(loc, getPoint_internal(pa, 0), pasize);\n\t\tloc += pasize;\n\n\t}\n\n\tif (retsize) *retsize = size;\n}\n\n\n/* find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN) */\nBOX3D *\nlwpoly_compute_box3d(LWPOLY *poly)\n{\n\tBOX3D *result;\n\n\t/* just need to check outer ring -- interior rings are inside */\n\tPOINTARRAY *pa = poly->rings[0];  \n\tresult  = ptarray_compute_box3d(pa);\n\n\treturn result;\n}\n\n/* find length of this serialized polygon */\nsize_t\nlwgeom_size_poly(const uchar *serialized_poly)\n{\n\tuint32 result = 1; /* char type */\n\tuint32 nrings;\n\tint ndims;\n\tint t;\n\tuchar type;\n\tuint32 npoints;\n\tconst uchar *loc;\n\n\tif (serialized_poly == NULL)\n\t\treturn -9999;\n\n\n\ttype = (uchar) serialized_poly[0];\n\tndims = lwgeom_ndims(type);\n\n\tif ( lwgeom_getType(type) != POLYGONTYPE)\n\t\treturn -9999;\n\n\n\tloc = serialized_poly+1;\n\n\tif (lwgeom_hasBBOX(type))\n\t{\n\t\tLWDEBUG(3, \"lwgeom_size_poly: has bbox\");\n\n\t\tloc += sizeof(BOX2DFLOAT4);\n\t\tresult +=sizeof(BOX2DFLOAT4);\n\t}\n\n\n\tif ( lwgeom_hasSRID(type))\n\t{\n\t\tLWDEBUG(3, \"lwgeom_size_poly: has srid\");\n\n\t\tloc +=4; /* type + SRID */\n\t\tresult += 4;\n\t}\n\n\n\tnrings = lw_get_uint32(loc);\n\tloc +=4;\n\tresult +=4;\n\n        LWDEBUGF(3, \"lwgeom_size_poly contains %d rings\", nrings);\n\n\tfor (t =0;t<nrings;t++)\n\t{\n\t\t/* read in a single ring and make a PA */\n\t\tnpoints = lw_get_uint32(loc);\n\t\tloc += 4;\n\t\tresult += 4;\n\n\t\tif (ndims == 3)\n\t\t{\n\t\t\tloc += 24*npoints;\n\t\t\tresult += 24*npoints;\n\t\t}\n\t\telse if (ndims == 2)\n\t\t{\n\t\t\tloc += 16*npoints;\n\t\t\tresult += 16*npoints;\n\t\t}\n\t\telse if (ndims == 4)\n\t\t{\n\t\t\tloc += 32*npoints;\n\t\t\tresult += 32*npoints;\n\t\t}\n\t}\n\n        LWDEBUGF(3, \"lwgeom_size_poly returning %d\", result);\n\n\treturn result;\n}\n\n/* find length of this deserialized polygon */\nsize_t\nlwpoly_serialize_size(LWPOLY *poly)\n{\n\tsize_t size = 1; /* type */\n\tuint32 i;\n\n\tif ( poly->SRID != -1 ) size += 4; /* SRID */\n\tif ( poly->bbox ) size += sizeof(BOX2DFLOAT4);\n\n\tLWDEBUGF(2, \"lwpoly_serialize_size called with poly[%p] (%d rings)\",\n\t\t\tpoly, poly->nrings);\n\n\tsize += 4; /* nrings */\n\n\tfor (i=0; i<poly->nrings; i++)\n\t{\n\t\tsize += 4; /* npoints */\n\t\tsize += poly->rings[i]->npoints*TYPE_NDIMS(poly->type)*sizeof(double);\n\t}\n\n\tLWDEBUGF(3, \"lwpoly_serialize_size returning %d\", size);\n\n\treturn size;\n}\n\nvoid lwpoly_free  (LWPOLY  *poly)\n{\n\tint t;\n\n\tif ( poly->bbox )\n\t\tlwfree(poly->bbox);\n\n\tfor (t=0;t<poly->nrings;t++)\n\t{\n\t\tif( poly->rings[t] )\n\t\t\tptarray_free(poly->rings[t]);\n\t}\n\n\tif ( poly->rings ) \n\t\tlwfree(poly->rings);\n\n\tlwfree(poly);\n}\n\nvoid printLWPOLY(LWPOLY *poly)\n{\n\tint t;\n\tlwnotice(\"LWPOLY {\");\n\tlwnotice(\"    ndims = %i\", (int)TYPE_NDIMS(poly->type));\n\tlwnotice(\"    SRID = %i\", (int)poly->SRID);\n\tlwnotice(\"    nrings = %i\", (int)poly->nrings);\n\tfor (t=0;t<poly->nrings;t++)\n\t{\n\t\tlwnotice(\"    RING # %i :\",t);\n\t\tprintPA(poly->rings[t]);\n\t}\n\tlwnotice(\"}\");\n}\n\nint\nlwpoly_compute_box2d_p(LWPOLY *poly, BOX2DFLOAT4 *box)\n{\n\tBOX2DFLOAT4 boxbuf;\n\tuint32 i;\n\n\tif ( ! poly->nrings ) return 0;\n\tif ( ! ptarray_compute_box2d_p(poly->rings[0], box) ) return 0;\n\tfor (i=1; i<poly->nrings; i++)\n\t{\n\t\tif ( ! ptarray_compute_box2d_p(poly->rings[0], &boxbuf) )\n\t\t\treturn 0;\n\t\tif ( ! box2d_union_p(box, &boxbuf, box) )\n\t\t\treturn 0;\n\t}\n\treturn 1;\n}\n\n/* Clone LWLINE object. POINTARRAY are not copied, it's ring array is. */\nLWPOLY *\nlwpoly_clone(const LWPOLY *g)\n{\n\tLWPOLY *ret = lwalloc(sizeof(LWPOLY));\n\tmemcpy(ret, g, sizeof(LWPOLY));\n\tret->rings = lwalloc(sizeof(POINTARRAY *)*g->nrings);\n\tmemcpy(ret->rings, g->rings, sizeof(POINTARRAY *)*g->nrings);\n\tif ( g->bbox ) ret->bbox = box2d_clone(g->bbox);\n\treturn ret;\n}\n\n/*\n * Add 'what' to this poly at position 'where'.\n * where=0 == prepend\n * where=-1 == append\n * Returns a MULTIPOLYGON or a GEOMETRYCOLLECTION\n */\nLWGEOM *\nlwpoly_add(const LWPOLY *to, uint32 where, const LWGEOM *what)\n{\n\tLWCOLLECTION *col;\n\tLWGEOM **geoms;\n\tint newtype;\n\n\tif ( where != -1 && where != 0 )\n\t{\n\t\tlwerror(\"lwpoly_add only supports 0 or -1 as second argument, got %d\", where);\n\t\treturn NULL;\n\t}\n\n\t/* dimensions compatibility are checked by caller */\n\n\t/* Construct geoms array */\n\tgeoms = lwalloc(sizeof(LWGEOM *)*2);\n\tif ( where == -1 ) /* append */\n\t{\n\t\tgeoms[0] = lwgeom_clone((LWGEOM *)to);\n\t\tgeoms[1] = lwgeom_clone(what);\n\t}\n\telse /* prepend */\n\t{\n\t\tgeoms[0] = lwgeom_clone(what);\n\t\tgeoms[1] = lwgeom_clone((LWGEOM *)to);\n\t}\n\n\t/* reset SRID and wantbbox flag from component types */\n\tgeoms[0]->SRID = geoms[1]->SRID = -1;\n\tTYPE_SETHASSRID(geoms[0]->type, 0);\n\tTYPE_SETHASSRID(geoms[1]->type, 0);\n\tTYPE_SETHASBBOX(geoms[0]->type, 0);\n\tTYPE_SETHASBBOX(geoms[1]->type, 0);\n\n\t/* Find appropriate geom type */\n\tif ( TYPE_GETTYPE(what->type) == POLYGONTYPE ) newtype = MULTIPOLYGONTYPE;\n\telse newtype = COLLECTIONTYPE;\n\n\tcol = lwcollection_construct(newtype,\n\t\tto->SRID, NULL,\n\t\t2, geoms);\n\t\n\treturn (LWGEOM *)col;\n}\n\nvoid\nlwpoly_forceRHR(LWPOLY *poly)\n{\n\tint i;\n\n\tif ( ptarray_isccw(poly->rings[0]) )\n\t{\n\t\tptarray_reverse(poly->rings[0]);\n\t}\n\n\tfor (i=1; i<poly->nrings; i++)\n\t{\n\t\tif ( ! ptarray_isccw(poly->rings[i]) )\n\t\t{\n\t\t\tptarray_reverse(poly->rings[i]);\n\t\t}\n\t}\n}\n\nvoid\nlwpoly_release(LWPOLY *lwpoly)\n{\n  lwgeom_release(lwpoly_as_lwgeom(lwpoly));\n}\n\nvoid\nlwpoly_reverse(LWPOLY *poly)\n{\n\tint i;\n\n\tfor (i=0; i<poly->nrings; i++)\n\t\tptarray_reverse(poly->rings[i]);\n}\n\nLWPOLY *\nlwpoly_segmentize2d(LWPOLY *poly, double dist)\n{\n\tPOINTARRAY **newrings;\n\tunsigned int i;\n\t\n\tnewrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);\n\tfor (i=0; i<poly->nrings; i++)\n\t{\n\t\tnewrings[i] = ptarray_segmentize2d(poly->rings[i], dist);\n\t}\n\treturn lwpoly_construct(poly->SRID, NULL,\n\t\tpoly->nrings, newrings);\n}\n\n/*\n * check coordinate equality \n * ring and coordinate order is considered\n */\nchar\nlwpoly_same(const LWPOLY *p1, const LWPOLY *p2)\n{\n\tunsigned int i;\n\n\tif ( p1->nrings != p2->nrings ) return 0;\n\tfor (i=0; i<p1->nrings; i++)\n\t{\n\t\tif ( ! ptarray_same(p1->rings[i], p2->rings[i]) )\n\t\t\treturn 0;\n\t}\n\treturn 1;\n}\n\n/*\n * Construct a polygon from a LWLINE being\n * the shell and an array of LWLINE (possibly NULL) being holes.\n * Pointarrays from intput geoms are cloned.\n * SRID must be the same for each input line.\n * Input lines must have at least 4 points, and be closed.\n */\nLWPOLY *\nlwpoly_from_lwlines(const LWLINE *shell,\n\tunsigned int nholes, const LWLINE **holes)\n{\n\tunsigned int nrings;\n\tPOINTARRAY **rings = lwalloc((nholes+1)*sizeof(POINTARRAY *));\n\tint SRID = shell->SRID;\n\tLWPOLY *ret;\n\n\tif ( shell->points->npoints < 4 )\n\t\tlwerror(\"lwpoly_from_lwlines: shell must have at least 4 points\");\n\tif ( ! ptarray_isclosed2d(shell->points) )\n\t\tlwerror(\"lwpoly_from_lwlines: shell must be closed\");\n\trings[0] = ptarray_clone(shell->points);\n\n\tfor (nrings=1; nrings<=nholes; nrings++)\n\t{\n\t\tconst LWLINE *hole = holes[nrings-1];\n\n\t\tif ( hole->SRID != SRID )\n\t\t\tlwerror(\"lwpoly_from_lwlines: mixed SRIDs in input lines\");\n\n\t\tif ( hole->points->npoints < 4 )\n\t\t\tlwerror(\"lwpoly_from_lwlines: holes must have at least 4 points\");\n\t\tif ( ! ptarray_isclosed2d(hole->points) )\n\t\t\tlwerror(\"lwpoly_from_lwlines: holes must be closed\");\n\n\t\trings[nrings] = ptarray_clone(hole->points);\n\t}\n\n\tret = lwpoly_construct(SRID, NULL, nrings, rings);\n\treturn ret;\n}\n"
  },
  {
    "path": "src/liblwgeom/lwsegmentize.c",
    "content": "/**********************************************************************\n * $Id: lwsegmentize.c 3807 2009-03-08 21:15:00Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n\n#include \"liblwgeom.h\"\n\n\ndouble interpolate_arc(double angle, double zm1, double a1, double zm2, double a2);\nPOINTARRAY *lwcircle_segmentize(POINT4D *p1, POINT4D *p2, POINT4D *p3, uint32 perQuad);\nLWLINE *lwcurve_segmentize(LWCIRCSTRING *icurve, uint32 perQuad);\nLWLINE *lwcompound_segmentize(LWCOMPOUND *icompound, uint32 perQuad);\nLWPOLY *lwcurvepoly_segmentize(LWCURVEPOLY *curvepoly, uint32 perQuad);\nLWMLINE *lwmcurve_segmentize(LWMCURVE *mcurve, uint32 perQuad);\nLWMPOLY *lwmsurface_segmentize(LWMSURFACE *msurface, uint32 perQuad);\nLWCOLLECTION *lwcollection_segmentize(LWCOLLECTION *collection, uint32 perQuad);\nLWGEOM *append_segment(LWGEOM *geom, POINTARRAY *pts, int type, int SRID);\nLWGEOM *pta_desegmentize(POINTARRAY *points, int type, int SRID);\nLWGEOM *lwline_desegmentize(LWLINE *line);\nLWGEOM *lwpolygon_desegmentize(LWPOLY *poly);\nLWGEOM *lwmline_desegmentize(LWMLINE *mline);\nLWGEOM *lwmpolygon_desegmentize(LWMPOLY *mpoly);\nLWGEOM *lwgeom_desegmentize(LWGEOM *geom);\n\n\n\n/*\n * Tolerance used to determine equality.\n */\n#define EPSILON_SQLMM 1e-8\n\n/*\n * Determines (recursively in the case of collections) whether the geometry\n * contains at least on arc geometry or segment.\n */\nuint32\nhas_arc(LWGEOM *geom)\n{\n        LWCOLLECTION *col;\n        int i;\n\n        LWDEBUG(2, \"has_arc called.\");\n\n        switch(lwgeom_getType(geom->type)) \n        {\n        case POINTTYPE:\n        case LINETYPE:\n        case POLYGONTYPE:\n        case MULTIPOINTTYPE:\n        case MULTILINETYPE:\n        case MULTIPOLYGONTYPE:\n                return 0;\n        case CIRCSTRINGTYPE:\n                return 1;\n        /* It's a collection that MAY contain an arc */\n        default:\n                col = (LWCOLLECTION *)geom;\n                for(i=0; i<col->ngeoms; i++)\n                {\n                        if(has_arc(col->geoms[i]) == 1) return 1;\n                }\n                return 0;\n        }\n}\n\n/*\n * Determines the center of the circle defined by the three given points.\n * In the event the circle is complete, the midpoint of the segment defined\n * by the first and second points is returned.  If the points are colinear,\n * as determined by equal slopes, then NULL is returned.  If the interior\n * point is coincident with either end point, they are taken as colinear.\n */\ndouble\nlwcircle_center(POINT4D *p1, POINT4D *p2, POINT4D *p3, POINT4D **result)\n{\n        POINT4D *c;\n        double cx, cy, cr;\n        double temp, bc, cd, det;\n        \n        LWDEBUGF(2, \"lwcircle_center called (%.16f, %.16f), (%.16f, %.16f), (%.16f, %.16f).\", p1->x, p1->y, p2->x, p2->y, p3->x, p3->y);\n\n        /* Closed circle */\n        if(fabs(p1->x - p3->x) < EPSILON_SQLMM\n                        && fabs(p1->y - p3->y) < EPSILON_SQLMM)\n        {\n                cx = p1->x + (p2->x - p1->x) / 2.0;\n                cy = p1->y + (p2->y - p1->y) / 2.0;\n                c = lwalloc(sizeof(POINT2D));\n                c->x = cx;\n                c->y = cy;\n                *result = c;\n                cr = sqrt((cx-p1->x)*(cx-p1->x)+(cy-p1->y)*(cy-p1->y));\n                return cr;\n        }\n\n        temp = p2->x*p2->x + p2->y*p2->y;\n        bc = (p1->x*p1->x + p1->y*p1->y - temp) / 2.0;\n        cd = (temp - p3->x*p3->x - p3->y*p3->y) / 2.0;\n        det = (p1->x - p2->x)*(p2->y - p3->y)-(p2->x - p3->x)*(p1->y - p2->y);\n\n        /* Check colinearity */\n        if(fabs(det) < EPSILON_SQLMM)\n        {\n                *result = NULL;\n                return -1.0;\n        }\n\n        det = 1.0 / det;\n        cx = (bc*(p2->y - p3->y)-cd*(p1->y - p2->y))*det;\n        cy = ((p1->x - p2->x)*cd-(p2->x - p3->x)*bc)*det;\n        c = lwalloc(sizeof(POINT4D));\n        c->x = cx;\n        c->y = cy;\n        *result = c;\n        cr = sqrt((cx-p1->x)*(cx-p1->x)+(cy-p1->y)*(cy-p1->y));\n        return cr;\n}\n\ndouble\ninterpolate_arc(double angle, double zm1, double a1, double zm2, double a2)\n{\n        double frac = fabs((angle - a1) / (a2 - a1));\n        double result = frac * (zm2 - zm1) + zm1;\n\n        LWDEBUG(2, \"interpolate_arc called.\");\n\n        LWDEBUGF(3, \"interpolate_arc: angle=%.16f, a1=%.16f, a2=%.16f, z1=%.16f, z2=%.16f, frac=%.16f, result=%.16f\", angle, a1, a2, zm1, zm2, frac, result);\n\n        return result;\n}\n\n/*******************************************************************************\n * Begin curve segmentize functions\n ******************************************************************************/\n\nPOINTARRAY *\nlwcircle_segmentize(POINT4D *p1, POINT4D *p2, POINT4D *p3, uint32 perQuad)\n{\n        POINTARRAY *result;\n        POINT4D pbuf;\n        size_t ptsize = sizeof(POINT4D);\n        unsigned int ptcount;\n        uchar *pt;\n\n        POINT4D *center;\n        double radius = 0.0, \n               sweep = 0.0,\n               angle = 0.0,\n               increment = 0.0;\n        double a1, a2, a3, i;\n\n        LWDEBUG(2, \"lwcircle_segmentize called. \");\n\n        radius = lwcircle_center(p1, p2, p3, &center);\n\n        LWDEBUGF(3, \"lwcircle_segmentize, (%.16f, %.16f) radius=%.16f\", center->x, center->y, radius);\n\n        if(radius < 0)\n        {\n                return NULL;\n        }\n\n        a1 = atan2(p1->y - center->y, p1->x - center->x);\n        a2 = atan2(p2->y - center->y, p2->x - center->x);\n        a3 = atan2(p3->y - center->y, p3->x - center->x);\n\n        LWDEBUGF(3, \"a1 = %.16f, a2 = %.16f, a3 = %.16f\", a1, a2, a3);\n\n        if(fabs(p1->x - p3->x) < EPSILON_SQLMM\n                        && fabs(p1->y - p3->y) < EPSILON_SQLMM)\n        {\n                sweep = 2*M_PI;\n        }\n        /* Clockwise */\n        else if(a1 > a2 && a2 > a3) \n        {\n                sweep = a3 - a1;\n        }\n        /* Counter-clockwise */\n        else if(a1 < a2 && a2 < a3)\n        {\n                sweep = a3 - a1;\n        }\n        /* Clockwise, wrap */\n        else if((a1 < a2 && a1 > a3) || (a2 < a3 && a1 > a3))\n        {\n                sweep = a3 - a1 + 2*M_PI;\n        }\n        /* Counter-clockwise, wrap */\n        else if((a1 > a2 && a1 < a3) || (a2 > a3 && a1 < a3))\n        {\n                sweep = a3 - a1 - 2*M_PI;\n        } \n        else \n        {\n                sweep = 0.0;\n        }\n         \n        ptcount = ceil(fabs(perQuad * sweep / M_PI_2));\n        \n        result = ptarray_construct(1, 1, ptcount);\n\n        increment = M_PI_2 / perQuad;\n        if(sweep < 0) increment *= -1.0;\n        angle = a1;\n\n        LWDEBUGF(3, \"ptcount: %d, perQuad: %d, sweep: %.16f, increment: %.16f\", ptcount, perQuad, sweep, increment);\n\n        for(i = 0; i < ptcount - 1; i++)\n        {\n            pt = getPoint_internal(result, i);\n            angle += increment;\n            if(increment > 0.0 && angle > M_PI) angle -= 2*M_PI;\n            if(increment < 0.0 && angle < -1*M_PI) angle -= 2*M_PI;\n            pbuf.x = center->x + radius*cos(angle);\n            pbuf.y = center->y + radius*sin(angle);\n            if((sweep > 0 && angle < a2) || (sweep < 0 && angle > a2))\n            {\n                if((sweep > 0 && a1 < a2) || (sweep < 0 && a1 > a2))\n                {\n                        pbuf.z = interpolate_arc(angle, p1->z, a1, p2->z, a2);\n                        pbuf.m = interpolate_arc(angle, p1->m, a1, p2->m, a2);\n                }\n                else\n                {\n                    if(sweep > 0)\n                    {\n                        pbuf.z = interpolate_arc(angle, p1->z, a1-(2*M_PI), p2->z, a2);\n                        pbuf.m = interpolate_arc(angle, p1->m, a1-(2*M_PI), p2->m, a2);\n                    }\n                    else\n                    {\n                        pbuf.z = interpolate_arc(angle, p1->z, a1+(2*M_PI), p2->z, a2);\n                        pbuf.m = interpolate_arc(angle, p1->m, a1+(2*M_PI), p2->m, a2);\n                    }\n                }\n            }\n            else\n            {\n                if((sweep > 0 && a2 < a3) || (sweep < 0 && a2 > a3))\n                {\n                    pbuf.z = interpolate_arc(angle, p2->z, a2, p3->z, a3);\n                    pbuf.m = interpolate_arc(angle, p2->m, a2, p3->m, a3);\n                }\n                else\n                {\n                    if(sweep > 0)\n                    {\n                        pbuf.z = interpolate_arc(angle, p2->z, a2-(2*M_PI), p3->z, a3);\n                        pbuf.m = interpolate_arc(angle, p2->m, a2-(2*M_PI), p3->m, a3);\n                    }\n                    else\n                    {\n                        pbuf.z = interpolate_arc(angle, p2->z, a2+(2*M_PI), p3->z, a3);\n                        pbuf.m = interpolate_arc(angle, p2->m, a2+(2*M_PI), p3->m, a3);\n                    }\n                }\n            }\n            memcpy(pt, (uchar *)&pbuf, ptsize);\n        }\n\n        pt = getPoint_internal(result, ptcount - 1);\n        memcpy(pt, (uchar *)p3, ptsize);\n\n        lwfree(center);\n\n        return result;\n}\n\nLWLINE *\nlwcurve_segmentize(LWCIRCSTRING *icurve, uint32 perQuad)\n{\n        LWLINE *oline;\n        DYNPTARRAY *ptarray;\n        POINTARRAY *tmp;\n        uint32 i, j;\n        POINT4D *p1 = lwalloc(sizeof(POINT4D));\n        POINT4D *p2 = lwalloc(sizeof(POINT4D));\n        POINT4D *p3 = lwalloc(sizeof(POINT4D));\n        POINT4D *p4 = lwalloc(sizeof(POINT4D));\n\n\n        LWDEBUGF(2, \"lwcurve_segmentize called., dim = %d\", icurve->points->dims);\n\n        ptarray = dynptarray_create(icurve->points->npoints, icurve->points->dims);\n        if(!getPoint4d_p(icurve->points, 0, p4))\n        {\n                lwerror(\"lwcurve_segmentize: Cannot extract point.\");\n        }\n        dynptarray_addPoint4d(ptarray, p4, 1);\n\n        for(i = 2; i < icurve->points->npoints; i+=2) \n        {\n                LWDEBUGF(3, \"lwcurve_segmentize: arc ending at point %d\", i);\n\n                getPoint4d_p(icurve->points, i - 2, p1);\n                getPoint4d_p(icurve->points, i - 1, p2);\n                getPoint4d_p(icurve->points, i, p3);\n                tmp = lwcircle_segmentize(p1, p2, p3, perQuad);\n\n                LWDEBUGF(3, \"lwcurve_segmentize: generated %d points\", tmp->npoints);\n\n                for(j = 0; j < tmp->npoints; j++)\n                {\n                        getPoint4d_p(tmp, j, p4);\n                        dynptarray_addPoint4d(ptarray, p4, 1);\n                }\n                lwfree(tmp);\n        }\n        oline = lwline_construct(icurve->SRID, NULL, ptarray_clone(ptarray->pa));\n\n        lwfree(p1);\n        lwfree(p2);\n        lwfree(p3);\n        lwfree(p4);\n        lwfree(ptarray);\n        return oline;\n}\n\nLWLINE *\nlwcompound_segmentize(LWCOMPOUND *icompound, uint32 perQuad)\n{\n        LWLINE *oline;\n        LWGEOM *geom;\n        DYNPTARRAY *ptarray = NULL;\n        LWLINE *tmp = NULL;\n        uint32 i, j;\n        POINT4D *p = NULL;\n\n        LWDEBUG(2, \"lwcompound_segmentize called.\");\n\n        p = lwalloc(sizeof(POINT4D));\n\n        ptarray = dynptarray_create(2, ((POINTARRAY *)icompound->geoms[0]->data)->dims);\n\n        for(i = 0; i < icompound->ngeoms; i++)\n        {\n                geom = icompound->geoms[i];\n                if(lwgeom_getType(geom->type) == CIRCSTRINGTYPE)\n                {\n                        tmp = lwcurve_segmentize((LWCIRCSTRING *)geom, perQuad);\n                        for(j = 0; j < tmp->points->npoints; j++)\n                        {\n                                getPoint4d_p(tmp->points, j, p);\n                                dynptarray_addPoint4d(ptarray, p, 0);\n                        }\n                        lwfree(tmp);\n                }\n                else if(lwgeom_getType(geom->type) == LINETYPE)\n                {\n                        tmp = (LWLINE *)geom;\n                        for(j = 0; j < tmp->points->npoints; j++)\n                        {\n                                getPoint4d_p(tmp->points, j, p);\n                                dynptarray_addPoint4d(ptarray, p, 0);\n                        }\n                }\n                else\n                {\n                        lwerror(\"Unsupported geometry type %d found.\", lwgeom_getType(geom->type));\n                        return NULL;\n                }\n        }\n        oline = lwline_construct(icompound->SRID, NULL, ptarray_clone(ptarray->pa));\n        lwfree(ptarray);\n        lwfree(p);\n        return oline;\n}\n\nLWPOLY *\nlwcurvepoly_segmentize(LWCURVEPOLY *curvepoly, uint32 perQuad)\n{\n        LWPOLY *ogeom;\n        LWGEOM *tmp;\n        LWLINE *line;\n        POINTARRAY **ptarray;\n        int i;\n\n        LWDEBUG(2, \"lwcurvepoly_segmentize called.\");\n\n        ptarray = lwalloc(sizeof(POINTARRAY *)*curvepoly->nrings);\n\n        for(i = 0; i < curvepoly->nrings; i++)\n        {\n                tmp = curvepoly->rings[i];\n                if(lwgeom_getType(tmp->type) == CIRCSTRINGTYPE)\n                {\n                        line = lwcurve_segmentize((LWCIRCSTRING *)tmp, perQuad);\n                        ptarray[i] = ptarray_clone(line->points);\n                        lwfree(line);\n                }\n                else if(lwgeom_getType(tmp->type) == LINETYPE)\n                {\n                        line = (LWLINE *)tmp;\n                        ptarray[i] = ptarray_clone(line->points);\n                }\n                else\n                {\n                        lwerror(\"Invalid ring type found in CurvePoly.\");\n                        return NULL;\n                }\n        }\n\n        ogeom = lwpoly_construct(curvepoly->SRID, NULL, curvepoly->nrings, ptarray);\n        return ogeom;\n}\n\nLWMLINE *\nlwmcurve_segmentize(LWMCURVE *mcurve, uint32 perQuad)\n{\n        LWMLINE *ogeom;\n        LWGEOM *tmp;\n        LWGEOM **lines;\n        int i;\n        \n        LWDEBUGF(2, \"lwmcurve_segmentize called, geoms=%d, dim=%d.\", mcurve->ngeoms, TYPE_NDIMS(mcurve->type));\n\n        lines = lwalloc(sizeof(LWGEOM *)*mcurve->ngeoms);\n\n        for(i = 0; i < mcurve->ngeoms; i++)\n        {\n                tmp = mcurve->geoms[i];\n                if(lwgeom_getType(tmp->type) == CIRCSTRINGTYPE)\n                {\n                        lines[i] = (LWGEOM *)lwcurve_segmentize((LWCIRCSTRING *)tmp, perQuad);\n                }\n                else if(lwgeom_getType(tmp->type) == LINETYPE)\n                {\n                        lines[i] = (LWGEOM *)lwline_construct(mcurve->SRID, NULL, ptarray_clone(((LWLINE *)tmp)->points));\n                }\n                else\n                {\n                        lwerror(\"Unsupported geometry found in MultiCurve.\");\n                        return NULL;\n                }\n        }\n\n        ogeom = (LWMLINE *)lwcollection_construct(MULTILINETYPE, mcurve->SRID, NULL, mcurve->ngeoms, lines);\n        return ogeom;\n}\n\nLWMPOLY *\nlwmsurface_segmentize(LWMSURFACE *msurface, uint32 perQuad)\n{\n        LWMPOLY *ogeom;\n        LWGEOM *tmp;\n        LWPOLY *poly;\n        LWGEOM **polys;\n        POINTARRAY **ptarray;\n        int i, j;\n\n        LWDEBUG(2, \"lwmsurface_segmentize called.\");\n\n        polys = lwalloc(sizeof(LWGEOM *)*msurface->ngeoms);\n\n        for(i = 0; i < msurface->ngeoms; i++)\n        {\n                tmp = msurface->geoms[i];\n                if(lwgeom_getType(tmp->type) == CURVEPOLYTYPE)\n                {\n                        polys[i] = (LWGEOM *)lwcurvepoly_segmentize((LWCURVEPOLY *)tmp, perQuad);\n                }\n                else if(lwgeom_getType(tmp->type) == POLYGONTYPE)\n                {\n                        poly = (LWPOLY *)tmp;\n                        ptarray = lwalloc(sizeof(POINTARRAY *)*poly->nrings);\n                        for(j = 0; j < poly->nrings; j++)\n                        {\n                                ptarray[j] = ptarray_clone(poly->rings[j]);\n                        }\n                        polys[i] = (LWGEOM *)lwpoly_construct(msurface->SRID, NULL, poly->nrings, ptarray);\n                }\n        }\n        ogeom = (LWMPOLY *)lwcollection_construct(MULTIPOLYGONTYPE, msurface->SRID, NULL, msurface->ngeoms, polys);\n        return ogeom;\n}\n\nLWCOLLECTION *\nlwcollection_segmentize(LWCOLLECTION *collection, uint32 perQuad)\n{\n        LWCOLLECTION *ocol;\n        LWGEOM *tmp;\n        LWGEOM **geoms;\n        int i;\n\n        LWDEBUG(2, \"lwcollection_segmentize called.\");\n\n        geoms = lwalloc(sizeof(LWGEOM *)*collection->ngeoms);\n\n        for(i=0; i<collection->ngeoms; i++)\n        {\n                tmp = collection->geoms[i];\n                switch(lwgeom_getType(tmp->type)) {\n                case CIRCSTRINGTYPE:\n                        geoms[i] = (LWGEOM *)lwcurve_segmentize((LWCIRCSTRING *)tmp, perQuad);\n                        break;\n                case COMPOUNDTYPE:\n                        geoms[i] = (LWGEOM *)lwcompound_segmentize((LWCOMPOUND *)tmp, perQuad);\n                        break;\n                case CURVEPOLYTYPE:\n                        geoms[i] = (LWGEOM *)lwcurvepoly_segmentize((LWCURVEPOLY *)tmp, perQuad);\n                        break;\n                case COLLECTIONTYPE:\n                        geoms[i] = (LWGEOM *)lwcollection_segmentize((LWCOLLECTION *)tmp, perQuad);\n                        break;\n                default:\n                        geoms[i] = lwgeom_clone(tmp);\n                        break;\n                }\n        }\n        ocol = lwcollection_construct(COLLECTIONTYPE, collection->SRID, NULL, collection->ngeoms, geoms);\n        return ocol;\n}\n\nLWGEOM *\nlwgeom_segmentize(LWGEOM *geom, uint32 perQuad)\n{\n        LWGEOM * ogeom = NULL;\n        switch(lwgeom_getType(geom->type)) {\n        case CIRCSTRINGTYPE:\n                ogeom = (LWGEOM *)lwcurve_segmentize((LWCIRCSTRING *)geom, perQuad);\n                break;\n        case COMPOUNDTYPE:\n                ogeom = (LWGEOM *)lwcompound_segmentize((LWCOMPOUND *)geom, perQuad);\n                break;\n        case CURVEPOLYTYPE:\n                ogeom = (LWGEOM *)lwcurvepoly_segmentize((LWCURVEPOLY *)geom, perQuad);\n                break;\n        case MULTICURVETYPE:\n                ogeom = (LWGEOM *)lwmcurve_segmentize((LWMCURVE *)geom, perQuad);\n                break;\n        case MULTISURFACETYPE:\n                ogeom = (LWGEOM *)lwmsurface_segmentize((LWMSURFACE *)geom, perQuad);\n                break;\n        case COLLECTIONTYPE:\n                ogeom = (LWGEOM *)lwcollection_segmentize((LWCOLLECTION *)geom, perQuad);\n                break;\n        default:\n                ogeom = lwgeom_clone(geom);\n        }\n        return ogeom;\n}\n\n/*******************************************************************************\n * End curve segmentize functions\n ******************************************************************************/\nLWGEOM *\nappend_segment(LWGEOM *geom, POINTARRAY *pts, int type, int SRID)\n{\n        LWGEOM *result; \n        int currentType, i;\n\n        LWDEBUGF(2, \"append_segment called %p, %p, %d, %d\", geom, pts, type, SRID);\n\n        if(geom == NULL)\n        {\n                if(type == LINETYPE)\n                {\n                        LWDEBUG(3, \"append_segment: line to NULL\");\n\n                        return (LWGEOM *)lwline_construct(SRID, NULL, pts);\n                }\n                else if(type == CIRCSTRINGTYPE)\n                {\n#if POSTGIS_DEBUG_LEVEL >= 4\n                        POINT4D tmp;\n                        \n\t\t\tLWDEBUGF(4, \"append_segment: curve to NULL %d\", pts->npoints);\n \n                        for(i=0; i<pts->npoints; i++)\n                        {\n                                getPoint4d_p(pts, i, &tmp);\n                                LWDEBUGF(4, \"new point: (%.16f,%.16f)\",tmp.x,tmp.y);\n                        }\n#endif\n                        return (LWGEOM *)lwcircstring_construct(SRID, NULL, pts);\n                }\n                else\n                {\n                        lwerror(\"Invalid segment type %d.\", type);\n                }\n        }\n        \n        currentType = lwgeom_getType(geom->type);\n        if(currentType == LINETYPE && type == LINETYPE)\n        {\n                POINTARRAY *newPoints;\n                POINT4D pt;\n                LWLINE *line = (LWLINE *)geom;\n\n                LWDEBUG(3, \"append_segment: line to line\");\n\n                newPoints = ptarray_construct(TYPE_HASZ(pts->dims), TYPE_HASM(pts->dims), pts->npoints + line->points->npoints - 1);\n                for(i=0; i<line->points->npoints; i++)\n                {\n                        getPoint4d_p(line->points, i, &pt);\n\t\t\t\t\t\tLWDEBUGF(5, \"copying to %p [%d]\", newPoints, i);\n                        setPoint4d(newPoints, i, &pt);\n                }\n                for(i=1; i<pts->npoints; i++)\n                {\n                        getPoint4d_p(pts, i, &pt);\n                        setPoint4d(newPoints, i + line->points->npoints - 1, &pt);\n                }\n                result = (LWGEOM *)lwline_construct(SRID, NULL, newPoints);\n                lwgeom_release(geom);\n                return result;\n        }\n        else if(currentType == CIRCSTRINGTYPE && type == CIRCSTRINGTYPE)\n        {\n                POINTARRAY *newPoints;\n                POINT4D pt;\n                LWCIRCSTRING *curve = (LWCIRCSTRING *)geom;\n\n                LWDEBUG(3, \"append_segment: circularstring to circularstring\");\n\n                newPoints = ptarray_construct(TYPE_HASZ(pts->dims), TYPE_HASM(pts->dims), pts->npoints + curve->points->npoints - 1);\n\n                LWDEBUGF(3, \"New array length: %d\", pts->npoints + curve->points->npoints - 1);\n\n                for(i=0; i<curve->points->npoints; i++)\n                {\n                        getPoint4d_p(curve->points, i, &pt);\n\n                        LWDEBUGF(3, \"orig point %d: (%.16f,%.16f)\", i, pt.x, pt.y);\n\n                        setPoint4d(newPoints, i, &pt);\n                }\n                for(i=1; i<pts->npoints;i++)\n                {\n                        getPoint4d_p(pts, i, &pt);\n\n                        LWDEBUGF(3, \"new point %d: (%.16f,%.16f)\", i + curve->points->npoints - 1, pt.x, pt.y);\n\n                        setPoint4d(newPoints, i + curve->points->npoints - 1, &pt);\n                }\n                result = (LWGEOM *)lwcircstring_construct(SRID, NULL, newPoints);\n                lwgeom_release(geom);\n                return result;\n        }\n        else if(currentType == CIRCSTRINGTYPE && type == LINETYPE)\n        {\n                LWLINE *line;\n                LWGEOM **geomArray;\n\n                LWDEBUG(3, \"append_segment: line to curve\");\n\n                geomArray = lwalloc(sizeof(LWGEOM *)*2);\n                geomArray[0] = lwgeom_clone(geom);\n                \n                line = lwline_construct(SRID, NULL, pts);\n                geomArray[1] = lwgeom_clone((LWGEOM *)line);\n\n                result = (LWGEOM *)lwcollection_construct(COMPOUNDTYPE, SRID, NULL, 2, geomArray);\n                lwfree((LWGEOM *)line);\n                lwgeom_release(geom);\n                return result;\n        }\n        else if(currentType == LINETYPE && type == CIRCSTRINGTYPE)\n        {\n                LWCIRCSTRING *curve;\n                LWGEOM **geomArray;\n\n                LWDEBUG(3, \"append_segment: circularstring to line\");\n\n                geomArray = lwalloc(sizeof(LWGEOM *)*2);\n                geomArray[0] = lwgeom_clone(geom);\n\n                curve = lwcircstring_construct(SRID, NULL, pts);\n                geomArray[1] = lwgeom_clone((LWGEOM *)curve);\n\n                result = (LWGEOM *)lwcollection_construct(COMPOUNDTYPE, SRID, NULL, 2, geomArray);\n                lwfree((LWGEOM *)curve);\n                lwgeom_release(geom);\n                return result;\n        }\n        else if(currentType == COMPOUNDTYPE)\n        {\n                LWGEOM *newGeom;\n                LWCOMPOUND *compound;\n                int count;\n                LWGEOM **geomArray;\n                \n                compound = (LWCOMPOUND *)geom;\n                count = compound->ngeoms + 1;\n                geomArray = lwalloc(sizeof(LWGEOM *)*count);\n                for(i=0; i<compound->ngeoms; i++)\n                {\n                        geomArray[i] = lwgeom_clone(compound->geoms[i]);\n                }\n                if(type == LINETYPE)\n                {\n                        LWDEBUG(3, \"append_segment: line to compound\");\n\n                        newGeom = (LWGEOM *)lwline_construct(SRID, NULL, pts);\n                }\n                else if(type == CIRCSTRINGTYPE)\n                {\n                        LWDEBUG(3, \"append_segment: circularstring to compound\");\n\n                        newGeom = (LWGEOM *)lwcircstring_construct(SRID, NULL, pts);\n                }\n                else\n                {\n                        lwerror(\"Invalid segment type %d.\", type);\n                        return NULL;\n                }\n                geomArray[compound->ngeoms] = lwgeom_clone(newGeom);\n\n                result = (LWGEOM *)lwcollection_construct(COMPOUNDTYPE, SRID, NULL, count, geomArray);\n                lwfree(newGeom);\n                lwgeom_release(geom);\n                return result;\n        }\n        lwerror(\"Invalid state %d-%d\", currentType, type);\n        return NULL;\n}\n\nLWGEOM *\npta_desegmentize(POINTARRAY *points, int type, int SRID)\n{\n        int i, j, commit, isline, count;\n        double last_angle, last_length;\n        double dxab, dyab, dxbc, dybc, theta, length;\n        POINT4D a, b, c, tmp;\n        POINTARRAY *pts;\n        LWGEOM *geom = NULL;\n\n        LWDEBUG(2, \"pta_desegmentize called.\");\n\n        getPoint4d_p(points, 0, &a);\n        getPoint4d_p(points, 1, &b);\n        getPoint4d_p(points, 2, &c);\n\n        dxab = b.x - a.x;\n        dyab = b.y - a.y;\n        dxbc = c.x - b.x;\n        dybc = c.y - b.y;\n\n        theta = atan2(dyab, dxab);\n        last_angle = theta - atan2(dybc, dxbc);\n        last_length = sqrt(dxbc*dxbc+dybc*dybc);\n        length = sqrt(dxab*dxab+dyab*dyab);\n        if((last_length - length) < EPSILON_SQLMM) \n        {\n                isline = -1;\n                LWDEBUG(3, \"Starting as unknown.\");\n        }\n        else \n        {\n                isline = 1;        \n                LWDEBUG(3, \"Starting as line.\");\n        }\n\n        commit = 0;\n        for(i=3; i<points->npoints; i++)\n        {\n                getPoint4d_p(points, i-2, &a);\n                getPoint4d_p(points, i-1, &b);\n                getPoint4d_p(points, i, &c);\n        \n                dxab = b.x - a.x;\n                dyab = b.y - a.y;\n                dxbc = c.x - b.x;\n                dybc = c.y - b.y;\n\n                LWDEBUGF(3, \"(dxab, dyab, dxbc, dybc) (%.16f, %.16f, %.16f, %.16f)\", dxab, dyab, dxbc, dybc);\n\n                theta = atan2(dyab, dxab);\n                theta = theta - atan2(dybc, dxbc);\n                length = sqrt(dxbc*dxbc+dybc*dybc);\n\n                LWDEBUGF(3, \"Last/current length and angle %.16f/%.16f, %.16f/%.16f\", last_angle, theta, last_length, length);\n\n                /* Found a line segment */\n                if(fabs(length - last_length) > EPSILON_SQLMM || \n                        fabs(theta - last_angle) > EPSILON_SQLMM)\n                {\n                        last_length = length;\n                        last_angle = theta;\n                        /* We are tracking a line, keep going */\n                        if(isline > 0)\n                        {\n                        }\n                        /* We were tracking a circularstring, commit it and start line*/\n                        else if(isline == 0)\n                        {\n                                LWDEBUGF(3, \"Building circularstring, %d - %d\", commit, i);\n\n                                count = i - commit;\n                                pts = ptarray_construct(\n                                        TYPE_HASZ(type),\n                                        TYPE_HASM(type),\n                                        3);\n                                getPoint4d_p(points, commit, &tmp);\n                                setPoint4d(pts, 0, &tmp);\n                                getPoint4d_p(points, \n                                        commit + count/2, &tmp);\n                                setPoint4d(pts, 1, &tmp);\n                                getPoint4d_p(points, i - 1, &tmp);\n                                setPoint4d(pts, 2, &tmp);\n\n                                commit = i-1;\n                                geom = append_segment(geom, pts, CIRCSTRINGTYPE, SRID);\n                                isline = -1;\n\n                                /* \n                                 * We now need to move ahead one point to \n                                 * determine if it's a potential new curve, \n                                 * since the last_angle value is corrupt.\n                                 */\n        i++;\n        getPoint4d_p(points, i-2, &a);\n        getPoint4d_p(points, i-1, &b);\n        getPoint4d_p(points, i, &c);\n\n        dxab = b.x - a.x;\n        dyab = b.y - a.y;\n        dxbc = c.x - b.x;\n        dybc = c.y - b.y;\n\n        theta = atan2(dyab, dxab);\n        last_angle = theta - atan2(dybc, dxbc);\n        last_length = sqrt(dxbc*dxbc+dybc*dybc);\n        length = sqrt(dxab*dxab+dyab*dyab);\n        if((last_length - length) < EPSILON_SQLMM) \n        {\n                isline = -1;\n                LWDEBUG(3, \"Restarting as unknown.\");\n        }\n        else \n        {\n                isline = 1;        \n                LWDEBUG(3, \"Restarting as line.\");\n        }\n\n\n                        }\n                        /* We didn't know what we were tracking, now we do. */\n                        else\n                        {\n                                LWDEBUG(3, \"It's a line\");\n                                isline = 1;\n                        }\n                }\n                /* Found a circularstring segment */\n                else\n                {\n                        /* We were tracking a circularstring, commit it and start line */\n                        if(isline > 0)\n                        {\n                                LWDEBUGF(3, \"Building line, %d - %d\", commit, i-2);\n\n                                count = i - commit - 2;\n\n                                pts = ptarray_construct(\n                                        TYPE_HASZ(type),\n                                        TYPE_HASM(type),\n                                        count);\n                                for(j=commit;j<i-2;j++)\n                                {\n                                        getPoint4d_p(points, j, &tmp);\n                                        setPoint4d(pts, j-commit, &tmp);\n                                }\n\n                                commit = i-3;\n                                geom = append_segment(geom, pts, LINETYPE, SRID);\n                                isline = -1;\n                        }\n                        /* We are tracking a circularstring, keep going */\n                        else if(isline == 0)\n                        {\n                                ;\n                        }\n                        /* We didn't know what we were tracking, now we do */\n                        else\n                        {\n                                LWDEBUG(3, \"It's a circularstring\");\n                                isline = 0;\n                        }\n                }\n        }\n        count = i - commit;\n        if(isline == 0 && count > 2)\n        {\n                LWDEBUGF(3, \"Finishing circularstring %d,%d.\", commit, i);\n\n                pts = ptarray_construct(\n                        TYPE_HASZ(type),\n                        TYPE_HASM(type),\n                        3);\n                getPoint4d_p(points, commit, &tmp);\n                setPoint4d(pts, 0, &tmp);\n                getPoint4d_p(points, commit + count/2, &tmp);\n                setPoint4d(pts, 1, &tmp);\n                getPoint4d_p(points, i - 1, &tmp);\n                setPoint4d(pts, 2, &tmp);\n\n                geom = append_segment(geom, pts, CIRCSTRINGTYPE, SRID);\n        }\n        else \n        {\n                LWDEBUGF(3, \"Finishing line %d,%d.\", commit, i);\n\n                pts = ptarray_construct(\n                        TYPE_HASZ(type),\n                        TYPE_HASM(type),\n                        count);\n                for(j=commit;j<i;j++)\n                {\n                        getPoint4d_p(points, j, &tmp);\n                        setPoint4d(pts, j-commit, &tmp);\n                }\n                geom = append_segment(geom, pts, LINETYPE, SRID);\n        }\n        return geom;\n}\n\nLWGEOM *\nlwline_desegmentize(LWLINE *line)\n{\n        LWDEBUG(2, \"lwline_desegmentize called.\");\n\n        return pta_desegmentize(line->points, line->type, line->SRID);\n}\n\nLWGEOM *\nlwpolygon_desegmentize(LWPOLY *poly)\n{\n        LWGEOM **geoms;\n        int i, hascurve = 0;\n        \n        LWDEBUG(2, \"lwpolygon_desegmentize called.\");\n\n        geoms = lwalloc(sizeof(LWGEOM *)*poly->nrings);\n        for(i=0; i<poly->nrings; i++)\n        {\n                geoms[i] = pta_desegmentize(poly->rings[i], poly->type, poly->SRID);\n                if(lwgeom_getType(geoms[i]->type) == CIRCSTRINGTYPE ||\n                        lwgeom_getType(geoms[i]->type) == COMPOUNDTYPE)\n                {\n                        hascurve = 1;\n                }\n        }\n        if(hascurve == 0)\n        {\n                for(i=0; i<poly->nrings; i++)\n                {\n                        lwfree(geoms[i]);\n                }\n                return lwgeom_clone((LWGEOM *)poly);\n        }\n\n        return (LWGEOM *)lwcollection_construct(CURVEPOLYTYPE, poly->SRID, NULL, poly->nrings, geoms);\n}\n\nLWGEOM *\nlwmline_desegmentize(LWMLINE *mline)\n{\n        LWGEOM **geoms;\n        int i, hascurve = 0;\n\n        LWDEBUG(2, \"lwmline_desegmentize called.\");\n\n        geoms = lwalloc(sizeof(LWGEOM *)*mline->ngeoms);\n        for(i=0; i<mline->ngeoms; i++)\n        {\n                geoms[i] = lwline_desegmentize((LWLINE *)mline->geoms[i]);\n                if(lwgeom_getType(geoms[i]->type) == CIRCSTRINGTYPE ||\n                        lwgeom_getType(geoms[i]->type) == COMPOUNDTYPE)\n                {\n                        hascurve = 1;\n                }\n        }\n        if(hascurve == 0)\n        {\n                for(i=0; i<mline->ngeoms; i++)\n                {\n                        lwfree(geoms[i]);\n                }\n                return lwgeom_clone((LWGEOM *)mline);\n        }\n        return (LWGEOM *)lwcollection_construct(MULTICURVETYPE, mline->SRID, NULL, mline->ngeoms, geoms);\n}\n\nLWGEOM *\nlwmpolygon_desegmentize(LWMPOLY *mpoly)\n{\n        LWGEOM **geoms;\n        int i, hascurve = 0;\n\n        LWDEBUG(2, \"lwmpoly_desegmentize called.\");\n\n        geoms = lwalloc(sizeof(LWGEOM *)*mpoly->ngeoms);\n        for(i=0; i<mpoly->ngeoms; i++)\n        {\n                geoms[i] = lwpolygon_desegmentize((LWPOLY *)mpoly->geoms[i]);\n                if(lwgeom_getType(geoms[i]->type) == CURVEPOLYTYPE)\n                {\n                        hascurve = 1;\n                }\n        }\n        if(hascurve == 0)\n        {\n                for(i=0; i<mpoly->ngeoms; i++)\n                {\n                        lwfree(geoms[i]);\n                }\n                return lwgeom_clone((LWGEOM *)mpoly);\n        }\n        return (LWGEOM *)lwcollection_construct(MULTISURFACETYPE, mpoly->SRID, NULL, mpoly->ngeoms, geoms);\n}\n\nLWGEOM *\nlwgeom_desegmentize(LWGEOM *geom)\n{\n        int type = lwgeom_getType(geom->type);\n\n        LWDEBUG(2, \"lwgeom_desegmentize called.\");\n\n        switch(type) {\n        case LINETYPE:\n                return lwline_desegmentize((LWLINE *)geom);\n        case POLYGONTYPE:\n                return lwpolygon_desegmentize((LWPOLY *)geom);\n        case MULTILINETYPE:\n                return lwmline_desegmentize((LWMLINE *)geom);\n        case MULTIPOLYGONTYPE:\n                return lwmpolygon_desegmentize((LWMPOLY *)geom);\n        default:\n                return lwgeom_clone(geom);\n        }\n}\n\n"
  },
  {
    "path": "src/liblwgeom/lwutil.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include <string.h>\n\n\n/* Global variables */\n#include \"liblwgeom.h\"\n\nvoid *init_allocator(size_t size);\nvoid init_freeor(void *mem);\nvoid *init_reallocator(void *mem, size_t size);\nvoid init_noticereporter(const char *fmt, va_list ap);\nvoid init_errorreporter(const char *fmt, va_list ap);\n\nlwallocator lwalloc_var = init_allocator;\nlwreallocator lwrealloc_var = init_reallocator;\nlwfreeor lwfree_var = init_freeor;\nlwreporter lwnotice_var = init_noticereporter;\nlwreporter lwerror_var = init_errorreporter;\n\nstatic char *lwgeomTypeName[] = {\n\t\"Unknown\",\n\t\"Point\",\n\t\"Line\",\n\t\"Polygon\",\n\t\"MultiPoint\",\n\t\"MultiLine\",\n\t\"MultiPolygon\",\n\t\"GeometryCollection\",\n        \"CircularString\",\n        \"CompoundString\",\n        \"Invalid Type\",  /* POINTTYPEI */\n        \"Invalid Type\",  /* LINETYPEI */\n        \"Invalid Type\",  /* POLYTYPEI */\n        \"CurvePolygon\",\n        \"MultiCurve\",\n        \"MultiSurface\"\n};\n\n\n/*\n * lwnotice/lwerror handlers\n *\n * Since variadic functions cannot pass their parameters directly, we need\n * wrappers for these functions to convert the arguments into a va_list\n * structure.\n */\n\nvoid\nlwnotice(const char *fmt, ...)\n{\n\tva_list ap;\n\n\tva_start(ap, fmt);\n\n\t/* Call the supplied function */\n\t(*lwnotice_var)(fmt, ap);\n\n\tva_end(ap);\n}\n\nvoid\nlwerror(const char *fmt, ...)\n{\n\tva_list ap;\n\n\tva_start(ap, fmt);\n\n\t/* Call the supplied function */\n\t(*lwerror_var)(fmt, ap);\n\n\tva_end(ap);\n}\n\n/*\n * Initialisation allocators\n *\n * These are used the first time any of the allocators are called\n * to enable executables/libraries that link into liblwgeom to\n * be able to set up their own allocators. This is mainly useful\n * for older PostgreSQL versions that don't have functions that\n * are called upon startup.\n */\n\nvoid *\ninit_allocator(size_t size)\n{\n\tlwgeom_init_allocators();\n\n\treturn lwalloc_var(size);\n}\n\nvoid \ninit_freeor(void *mem)\n{\n\tlwgeom_init_allocators();\n\n\tlwfree_var(mem);\n}\n\nvoid *\ninit_reallocator(void *mem, size_t size)\n{\n\tlwgeom_init_allocators();\n\n\treturn lwrealloc_var(mem, size);\n}\n\nvoid\ninit_noticereporter(const char *fmt, va_list ap)\n{\n\tlwgeom_init_allocators();\n\n\t(*lwnotice_var)(fmt, ap);\n}\n\t\nvoid\ninit_errorreporter(const char *fmt, va_list ap)\n{\n\tlwgeom_init_allocators();\n\n\t(*lwerror_var)(fmt, ap);\n}\n\n\n/*\n * Default allocators\n *\n * We include some default allocators that use malloc/free/realloc\n * along with stdout/stderr since this is the most common use case\n *\n */\n\nvoid *\ndefault_allocator(size_t size)\n{\n\tvoid *mem = malloc(size);\n\treturn mem;\n}\n\nvoid\ndefault_freeor(void *mem)\n{\n\tfree(mem);\n}\n\nvoid *\ndefault_reallocator(void *mem, size_t size)\n{\n\tvoid *ret = realloc(mem, size);\n\treturn ret;\n}\n\nvoid\ndefault_noticereporter(const char *fmt, va_list ap)\n{\n\tchar *msg;\n\n\t/*\n\t * This is a GNU extension.\n\t * Dunno how to handle errors here.\n\t */\n\tif (!lw_vasprintf (&msg, fmt, ap))\n\t{\n\t\tva_end (ap);\n\t\treturn;\n\t}\n\tprintf(\"%s\\n\", msg);\n\tfree(msg);\n}\n\nvoid\ndefault_errorreporter(const char *fmt, va_list ap)\n{\n\tchar *msg;\n\n\t/*\n\t * This is a GNU extension.\n\t * Dunno how to handle errors here.\n\t */\n\tif (!lw_vasprintf (&msg, fmt, ap))\n\t{\n\t\tva_end (ap);\n\t\treturn;\n\t}\n\tfprintf(stderr, \"%s\\n\", msg);\n\tfree(msg);\n\texit(1);\n}\n\n\n/*\n * This function should be called from lwgeom_init_allocators() by programs\n * which wish to use the default allocators above\n */\n\nvoid lwgeom_install_default_allocators(void)\n{\n\tlwalloc_var = default_allocator;\n\tlwrealloc_var = default_reallocator;\n\tlwfree_var = default_freeor;\n\tlwerror_var = default_errorreporter;\t\n\tlwnotice_var = default_noticereporter;\n}\n \n\nconst char *\nlwgeom_typename(int type)\n{\n\t/* something went wrong somewhere */\n\tif ( type < 0 || type > 15 ) {\n\t\t/* assert(0); */\n\t\treturn \"Invalid type\";\n\t}\n\treturn lwgeomTypeName[type];\n}\n\nvoid *\nlwalloc(size_t size)\n{\n\tvoid *mem = lwalloc_var(size);\n\tLWDEBUGF(5, \"lwalloc: %d@%p\", size, mem);\n\treturn mem;\n}\n\nvoid *\nlwrealloc(void *mem, size_t size)\n{\n\tLWDEBUGF(5, \"lwrealloc: %d@%p\", size, mem);\n\treturn lwrealloc_var(mem, size);\n}\n\nvoid\nlwfree(void *mem)\n{\n\tlwfree_var(mem);\n}\n\n/*\n * Removes trailing zeros and dot for a %f formatted number.\n * Modifies input.\n */\nvoid\ntrim_trailing_zeros(char *str)\n{\n\tchar *ptr, *totrim=NULL;\n\tint len;\n\tint i;\n\n\tLWDEBUGF(3, \"input: %s\", str);\n\t\n\tptr = strchr(str, '.');\n\tif ( ! ptr ) return; /* no dot, no decimal digits */\n\n\tLWDEBUGF(3, \"ptr: %s\", ptr);\n\n\tlen = strlen(ptr);\n\tfor (i=len-1; i; i--)\n\t{\n\t\tif ( ptr[i] != '0' ) break;\n\t\ttotrim=&ptr[i];\n\t}\n\tif ( totrim )\n\t{\n\t\tif ( ptr == totrim-1 ) *ptr = '\\0';\n\t\telse *totrim = '\\0';\n\t}\n\t\n\tLWDEBUGF(3, \"output: %s\", str);\n}\n\n\n/*\n * Returns a new string which contains a maximum of maxlength characters starting \n * from startpos and finishing at endpos (0-based indexing). If the string is \n * truncated then the first or last characters are replaced by \"...\" as \n * appropriate.\n *\n * The caller should specify start or end truncation by setting the truncdirection\n * parameter as follows:\n *    0 - start truncation (i.e. characters are removed from the beginning)\n *    1 - end trunctation (i.e. characters are removed from the end)\n */  \n\nchar *lwmessage_truncate(char *str, int startpos, int endpos, int maxlength, int truncdirection)\n{\n\tchar *output;\n\tchar *outstart;\n\n\t/* Allocate space for new string */\n\toutput = lwalloc(maxlength + 4);\n\toutput[0] = '\\0';\n\n\t/* Start truncation */\n\tif (truncdirection == 0)\n\t{\n\t\t/* Calculate the start position */\n\t\tif (endpos - startpos < maxlength) \n\t\t{\n\t\t\toutstart = str + startpos;\n\t\t\tstrncat(output, outstart, endpos - startpos + 1); \n\t\t}\t\t\n\t\telse\n\t\t{\n\t\t\tif (maxlength >= 3)\n\t\t\t{\n\t\t\t\t/* Add \"...\" prefix */\n\t\t\t\toutstart = str + endpos + 1 - maxlength + 3;\n\t\t\t\tstrncat(output, \"...\", 3);\n\t\t\t\tstrncat(output, outstart, maxlength - 3); \n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* maxlength is too small; just output \"...\" */\n\t\t\t\tstrncat(output, \"...\", 3);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* End truncation */\n\tif (truncdirection == 1)\n\t{\n\t\t/* Calculate the end position */\n\t\tif (endpos - startpos < maxlength)\n\t\t{\n\t\t\toutstart = str + startpos;\n\t\t\tstrncat(output, outstart, endpos - startpos + 1);\n\t\t}\t\n\t\telse\n\t\t{\n\t\t\tif (maxlength >= 3)\n\t\t\t{\n\t\t\t\t/* Add \"...\" suffix */\n\t\t\t\toutstart = str + startpos;\t\n\t\t\t\tstrncat(output, outstart, maxlength - 3);\n\t\t\t\tstrncat(output, \"...\", 3); \n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* maxlength is too small; just output \"...\" */\n\t\t\t\tstrncat(output, \"...\", 3);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn output;\n}\n\n\nchar\ngetMachineEndian(void)\n{\n\tstatic int endian_check_int = 1; /* dont modify this!!! */\n\n\treturn *((char *) &endian_check_int); /* 0 = big endian | xdr,\n\t\t\t\t\t       * 1 = little endian | ndr\n\t                                       */\n}\n\n\nvoid\nerrorIfSRIDMismatch(int srid1, int srid2)\n{\n\tif ( srid1 != srid2 )\n\t{\n\t\tlwerror(\"Operation on mixed SRID geometries\");\n\t}\n}\n"
  },
  {
    "path": "src/liblwgeom/measures.c",
    "content": "/**********************************************************************\n * $Id: measures.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <math.h>\n#include <string.h>\n\n#include \"liblwgeom.h\"\n\n\n/*\n * pt_in_ring_2d(): crossing number test for a point in a polygon\n *      input:   p = a point,\n *               pa = vertex points of a ring V[n+1] with V[n]=V[0]\n *      returns: 0 = outside, 1 = inside\n *\n *\tOur polygons have first and last point the same,\n *\n */\nint pt_in_ring_2d(POINT2D *p, POINTARRAY *ring)\n{\n\tint cn = 0;    /* the crossing number counter */\n\tint i;\n\tPOINT2D v1, v2;\n\n#if INTEGRITY_CHECKS\n\tPOINT2D first, last;\n\n\tgetPoint2d_p(ring, 0, &first);\n\tgetPoint2d_p(ring, ring->npoints-1, &last);\n\tif ( memcmp(&first, &last, sizeof(POINT2D)) )\n\t{\n\t\tlwerror(\"pt_in_ring_2d: V[n] != V[0] (%g %g != %g %g)\",\n\t\t\tfirst.x, first.y, last.x, last.y);\n\t\t\t\n\t}\n#endif\n\n\tLWDEBUGF(2, \"pt_in_ring_2d called with point: %g %g\", p->x, p->y);\n\t/* printPA(ring); */\n\n\t/* loop through all edges of the polygon */\n\tgetPoint2d_p(ring, 0, &v1);\n    \tfor (i=0; i<ring->npoints-1; i++)\n\t{   \n\t\tdouble vt;\n\t\tgetPoint2d_p(ring, i+1, &v2);\n\n\t\t/* edge from vertex i to vertex i+1 */\n       \t\tif\n\t\t(\n\t\t\t/* an upward crossing */\n\t\t\t((v1.y <= p->y) && (v2.y > p->y))\n\t\t\t/* a downward crossing */\n       \t\t \t|| ((v1.y > p->y) && (v2.y <= p->y))\n\t\t)\n\t \t{\n\n\t\t\tvt = (double)(p->y - v1.y) / (v2.y - v1.y);\n\n\t\t\t/* P.x <intersect */\n\t\t\tif (p->x < v1.x + vt * (v2.x - v1.x))\n\t\t\t{\n\t\t\t\t/* a valid crossing of y=p.y right of p.x */\n           \t     \t\t++cn;\n\t\t\t}\n\t\t}\n\t\tv1 = v2;\n\t}\n\n\tLWDEBUGF(3, \"pt_in_ring_2d returning %d\", cn&1);\n\n\treturn (cn&1);    /* 0 if even (out), and 1 if odd (in) */\n}\n\ndouble distance2d_pt_pt(POINT2D *p1, POINT2D *p2)\n{\n\tdouble hside = p2->x - p1->x;\n\tdouble vside = p2->y - p1->y;\n\n\treturn sqrt ( hside*hside + vside*vside );\n\n\t/* the above is more readable\n\t   return sqrt(\n\t  \t(p2->x-p1->x) * (p2->x-p1->x) + (p2->y-p1->y) * (p2->y-p1->y)\n\t\t);  */\n}\n\n/*distance2d from p to line A->B */\ndouble distance2d_pt_seg(POINT2D *p, POINT2D *A, POINT2D *B)\n{\n\tdouble\tr,s;\n\n\t/*if start==end, then use pt distance */\n\tif (  ( A->x == B->x) && (A->y == B->y) )\n\t\treturn distance2d_pt_pt(p,A);\n\n\t/*\n\t * otherwise, we use comp.graphics.algorithms\n\t * Frequently Asked Questions method\n\t *\n\t *  (1)     \t      AC dot AB\n         *         r = ---------\n         *               ||AB||^2\n\t *\tr has the following meaning:\n\t *\tr=0 P = A\n\t *\tr=1 P = B\n\t *\tr<0 P is on the backward extension of AB\n\t *\tr>1 P is on the forward extension of AB\n\t *\t0<r<1 P is interior to AB\n\t */\n\n\tr = ( (p->x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );\n\n\tif (r<0) return distance2d_pt_pt(p,A);\n\tif (r>1) return distance2d_pt_pt(p,B);\n\n\n\t/*\n\t * (2)\n\t *\t     (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)\n\t *\ts = -----------------------------\n\t *\t             \tL^2\n\t *\n\t *\tThen the distance from C to P = |s|*L.\n\t *\n\t */\n\n\ts = ( (A->y-p->y)*(B->x-A->x)- (A->x-p->x)*(B->y-A->y) ) /\n\t\t( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );\n\n\treturn LW_ABS(s) * sqrt(\n\t\t(B->x-A->x)*(B->x-A->x) + (B->y-A->y)*(B->y-A->y)\n\t\t);\n}\n\n/* find the minimum 2d distance from AB to CD */\ndouble distance2d_seg_seg(POINT2D *A, POINT2D *B, POINT2D *C, POINT2D *D)\n{\n\n\tdouble\ts_top, s_bot,s;\n\tdouble\tr_top, r_bot,r;\n\n\tLWDEBUGF(2, \"distance2d_seg_seg [%g,%g]->[%g,%g] by [%g,%g]->[%g,%g]\",\n\t\tA->x,A->y,B->x,B->y, C->x,C->y, D->x, D->y);\n\n\n\t/*A and B are the same point */\n\tif (  ( A->x == B->x) && (A->y == B->y) )\n\t\treturn distance2d_pt_seg(A,C,D);\n\n\t\t/*U and V are the same point */\n\n\tif (  ( C->x == D->x) && (C->y == D->y) )\n\t\treturn distance2d_pt_seg(D,A,B);\n\n\t/* AB and CD are line segments */\n\t/* from comp.graphics.algo\n\n\tSolving the above for r and s yields\n\t\t\t\t(Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy)\n\t           r = ----------------------------- (eqn 1)\n\t\t\t\t(Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)\n\n\t\t \t(Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)\n\t\ts = ----------------------------- (eqn 2)\n\t\t\t(Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)\n\tLet P be the position vector of the intersection point, then\n\t\tP=A+r(B-A) or\n\t\tPx=Ax+r(Bx-Ax)\n\t\tPy=Ay+r(By-Ay)\n\tBy examining the values of r & s, you can also determine some other limiting conditions:\n\t\tIf 0<=r<=1 & 0<=s<=1, intersection exists\n\t\tr<0 or r>1 or s<0 or s>1 line segments do not intersect\n\t\tIf the denominator in eqn 1 is zero, AB & CD are parallel\n\t\tIf the numerator in eqn 1 is also zero, AB & CD are collinear.\n\n\t*/\n\tr_top = (A->y-C->y)*(D->x-C->x) - (A->x-C->x)*(D->y-C->y) ;\n\tr_bot = (B->x-A->x)*(D->y-C->y) - (B->y-A->y)*(D->x-C->x) ;\n\n\ts_top = (A->y-C->y)*(B->x-A->x) - (A->x-C->x)*(B->y-A->y);\n\ts_bot = (B->x-A->x)*(D->y-C->y) - (B->y-A->y)*(D->x-C->x);\n\n\tif  ( (r_bot==0) || (s_bot == 0) )\n\t{\n\t\treturn (\n\t\t\tLW_MIN(distance2d_pt_seg(A,C,D),\n\t\t\t\tLW_MIN(distance2d_pt_seg(B,C,D),\n\t\t\t\t\tLW_MIN(distance2d_pt_seg(C,A,B),\n\t\t\t\t\t\tdistance2d_pt_seg(D,A,B))\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n\ts = s_top/s_bot;\n\tr=  r_top/r_bot;\n\n\tif ((r<0) || (r>1) || (s<0) || (s>1) )\n\t{\n\t\t/*no intersection */\n\t\treturn (\n\t\t\tLW_MIN(distance2d_pt_seg(A,C,D),\n\t\t\t\tLW_MIN(distance2d_pt_seg(B,C,D),\n\t\t\t\t\tLW_MIN(distance2d_pt_seg(C,A,B),\n\t\t\t\t\t\tdistance2d_pt_seg(D,A,B))\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\n\t}\n\telse\n\t\treturn -0; /*intersection exists */\n\n}\n\n/*\n * search all the segments of pointarray to see which one is closest to p1\n * Returns minimum distance between point and pointarray\n */\ndouble distance2d_pt_ptarray(POINT2D *p, POINTARRAY *pa)\n{\n\tdouble result = 0;\n\tint t;\n\tPOINT2D\tstart, end;\n\n\tgetPoint2d_p(pa, 0, &start);\n\n\tfor (t=1; t<pa->npoints; t++)\n\t{\n\t\tdouble dist;\n\t\tgetPoint2d_p(pa, t, &end);\n\t\tdist = distance2d_pt_seg(p, &start, &end);\n\t\tif (t==1) result = dist;\n\t\telse result = LW_MIN(result, dist);\n\n\t\tif ( result == 0 ) return 0;\n\n\t\tstart = end;\n\t}\n\n\treturn result;\n}\n\n/* test each segment of l1 against each segment of l2.  Return min */\ndouble distance2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2)\n{\n\tdouble \tresult = 99999999999.9;\n\tchar result_okay = 0; /*result is a valid min */\n\tint t,u;\n\tPOINT2D\tstart, end;\n\tPOINT2D\tstart2, end2;\n\n\tLWDEBUGF(2, \"distance2d_ptarray_ptarray called (points: %d-%d)\",\n\t\t\tl1->npoints, l2->npoints);\n\n\tgetPoint2d_p(l1, 0, &start);\n\tfor (t=1; t<l1->npoints; t++) /*for each segment in L1 */\n\t{\n\t\tgetPoint2d_p(l1, t, &end);\n\n\t\tgetPoint2d_p(l2, 0, &start2);\n\t\tfor (u=1; u<l2->npoints; u++) /*for each segment in L2 */\n\t\t{\n\t\t\tdouble dist;\n\n\t\t\tgetPoint2d_p(l2, u, &end2);\n\n\t\t\tdist = distance2d_seg_seg(&start, &end, &start2, &end2);\n\n\t\t\tLWDEBUGF(4, \"line_line; seg %i * seg %i, dist = %g\\n\",t,u,dist);\n\n\t\t\tif (result_okay)\n\t\t\t\tresult = LW_MIN(result,dist);\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult_okay = 1;\n\t\t\t\tresult = dist;\n\t\t\t}\n\n\t\t\tLWDEBUGF(3, \" seg%d-seg%d dist: %f, mindist: %f\",\n\t\t\t\tt, u, dist, result);\n\n\t\t\tif (result <= 0) return 0; /*intersection */\n\n\t\t\tstart2 = end2;\n\t\t}\n\t\tstart = end;\n\t}\n\n\treturn result;\n}\n\n/* true if point is in poly (and not in its holes) */\nint pt_in_poly_2d(POINT2D *p, LWPOLY *poly)\n{\n\tint i;\n\n\t/* Not in outer ring */\n\tif ( ! pt_in_ring_2d(p, poly->rings[0]) ) return 0;\n\n\t/* Check holes */\n\tfor (i=1; i<poly->nrings; i++)\n\t{\n\t\t/* Inside a hole */\n\t\tif ( pt_in_ring_2d(p, poly->rings[i]) ) return 0;\n\t}\n\n\treturn 1; /* In outer ring, not in holes */\n}\n\n/*\n * Brute force.\n * Test line-ring distance against each ring.\n * If there's an intersection (distance==0) then return 0 (crosses boundary).\n * Otherwise, test to see if any point is inside outer rings of polygon,\n * but not in inner rings.\n * If so, return 0  (line inside polygon),\n * otherwise return min distance to a ring (could be outside\n * polygon or inside a hole)\n */\ndouble distance2d_ptarray_poly(POINTARRAY *pa, LWPOLY *poly)\n{\n\tPOINT2D pt;\n\tint i;\n\tdouble mindist = 0;\n\n\tLWDEBUGF(2, \"distance2d_ptarray_poly called (%d rings)\", poly->nrings);\n\n\tfor (i=0; i<poly->nrings; i++)\n\t{\n\t\tdouble dist = distance2d_ptarray_ptarray(pa, poly->rings[i]);\n\t\tif (i) mindist = LW_MIN(mindist, dist);\n\t\telse mindist = dist;\n\n\t\tLWDEBUGF(3, \" distance from ring %d: %f, mindist: %f\",\n\t\t\ti, dist, mindist);\n\n\t\tif ( mindist <= 0 ) return 0.0; /* intersection */\n\t}\n\n\t/*\n\t * No intersection, have to check if a point is\n\t * inside polygon\n\t */\n\tgetPoint2d_p(pa, 0, &pt);\n\n\t/*\n\t * Outside outer ring, so min distance to a ring\n\t * is the actual min distance\n\t */\n\tif ( ! pt_in_ring_2d(&pt, poly->rings[0]) ) return mindist;\n\n\n\t/*\n\t * Its in the outer ring.\n\t * Have to check if its inside a hole\n\t */\n\tfor (i=1; i<poly->nrings; i++)\n\t{\n\t\tif ( pt_in_ring_2d(&pt, poly->rings[i]) )\n\t\t{\n\t\t\t/*\n\t\t\t * Its inside a hole, then the actual\n\t\t\t * distance is the min ring distance\n\t\t\t */\n\t\t\treturn mindist;\n\t\t}\n\t}\n\n\treturn 0.0; /* Not in hole, so inside polygon */\n}\n\ndouble distance2d_point_point(LWPOINT *point1, LWPOINT *point2)\n{\n\tPOINT2D p1;\n\tPOINT2D p2;\n\n\tgetPoint2d_p(point1->point, 0, &p1);\n\tgetPoint2d_p(point2->point, 0, &p2);\n\n\treturn distance2d_pt_pt(&p1, &p2);\n}\n\ndouble distance2d_point_line(LWPOINT *point, LWLINE *line)\n{\n\tPOINT2D p;\n\tPOINTARRAY *pa = line->points;\n\tgetPoint2d_p(point->point, 0, &p);\n\treturn distance2d_pt_ptarray(&p, pa);\n}\n\ndouble distance2d_line_line(LWLINE *line1, LWLINE *line2)\n{\n\tPOINTARRAY *pa1 = line1->points;\n\tPOINTARRAY *pa2 = line2->points;\n\treturn distance2d_ptarray_ptarray(pa1, pa2);\n}\n\n/*\n * 1. see if pt in outer boundary. if no, then treat the outer ring like a line\n * 2. if in the boundary, test to see if its in a hole.\n *    if so, then return dist to hole, else return 0 (point in polygon)\n */\ndouble distance2d_point_poly(LWPOINT *point, LWPOLY *poly)\n{\n\tPOINT2D p;\n\tint i;\n\n\tgetPoint2d_p(point->point, 0, &p);\n\n\tLWDEBUG(2, \"distance2d_point_poly called\");\n\n\t/* Return distance to outer ring if not inside it */\n\tif ( ! pt_in_ring_2d(&p, poly->rings[0]) )\n\t{\n\t\tLWDEBUG(3, \" not inside outer-ring\");\n\n\t\treturn distance2d_pt_ptarray(&p, poly->rings[0]);\n\t}\n\n\t/*\n\t * Inside the outer ring.\n\t * Scan though each of the inner rings looking to\n\t * see if its inside.  If not, distance==0.\n\t * Otherwise, distance = pt to ring distance\n\t */\n\tfor (i=1; i<poly->nrings; i++) \n\t{\n\t\t/* Inside a hole. Distance = pt -> ring */\n\t\tif ( pt_in_ring_2d(&p, poly->rings[i]) )\n\t\t{\n\t\t\tLWDEBUG(3, \" inside an hole\");\n\n\t\t\treturn distance2d_pt_ptarray(&p, poly->rings[i]);\n\t\t}\n\t}\n\n\tLWDEBUG(3, \" inside the polygon\");\n\n\treturn 0.0; /* Is inside the polygon */\n}\n\n/*\n * Brute force.\n * Test to see if any rings intersect.\n * If yes, dist=0.\n * Test to see if one inside the other and if they are inside holes.\n * Find min distance ring-to-ring.\n */\ndouble distance2d_poly_poly(LWPOLY *poly1, LWPOLY *poly2)\n{\n\tPOINT2D pt;\n\tdouble mindist = -1;\n\tint i;\n\n\tLWDEBUG(2, \"distance2d_poly_poly called\");\n\n\t/* if poly1 inside poly2 return 0 */\n\tgetPoint2d_p(poly1->rings[0], 0, &pt);\n\tif ( pt_in_poly_2d(&pt, poly2) ) return 0.0;  \n\n\t/* if poly2 inside poly1 return 0 */\n\tgetPoint2d_p(poly2->rings[0], 0, &pt);\n\tif ( pt_in_poly_2d(&pt, poly1) ) return 0.0;  \n\n\tLWDEBUG(3, \"  polys not inside each other\");\n\n\t/*\n\t * foreach ring in Poly1\n\t * foreach ring in Poly2\n\t *   if intersect, return 0\n\t */\n\tfor (i=0; i<poly1->nrings; i++)\n\t{\n\t\tint j;\n\t\tfor (j=0; j<poly2->nrings; j++)\n\t\t{\n\t\t\tdouble d = distance2d_ptarray_ptarray(poly1->rings[i],\n\t\t\t\tpoly2->rings[j]);\n\t\t\tif ( d <= 0 ) return 0.0;\n\n\t\t\t/* mindist is -1 when not yet set */\n\t\t\tif (mindist > -1) mindist = LW_MIN(mindist, d);\n\t\t\telse mindist = d;\n\n\t\t\tLWDEBUGF(3, \"  ring%i-%i dist: %f, mindist: %f\", i, j, d, mindist);\n\t\t}\n\n\t}\n\n\t/* otherwise return closest approach of rings (no intersection) */\n\treturn mindist;\n\n}\n\ndouble distance2d_line_poly(LWLINE *line, LWPOLY *poly)\n{\n\treturn distance2d_ptarray_poly(line->points, poly);\n}\n\n\n/*find the 2d length of the given POINTARRAY (even if it's 3d) */\ndouble lwgeom_pointarray_length2d(POINTARRAY *pts)\n{\n\tdouble dist = 0.0;\n\tint i;\n\tPOINT2D frm;\n\tPOINT2D to;\n\n\tif ( pts->npoints < 2 ) return 0.0;\n\tfor (i=0; i<pts->npoints-1;i++)\n\t{\n\t\tgetPoint2d_p(pts, i, &frm);\n\t\tgetPoint2d_p(pts, i+1, &to);\n\t\tdist += sqrt( ( (frm.x - to.x)*(frm.x - to.x) )  +\n\t\t\t\t((frm.y - to.y)*(frm.y - to.y) ) );\n\t}\n\treturn dist;\n}\n\n/*\n * Find the 3d/2d length of the given POINTARRAY\n * (depending on its dimensions)\n */\ndouble\nlwgeom_pointarray_length(POINTARRAY *pts)\n{\n\tdouble dist = 0.0;\n\tint i;\n\tPOINT3DZ frm;\n\tPOINT3DZ to;\n\n\tif ( pts->npoints < 2 ) return 0.0;\n\n\t/* compute 2d length if 3d is not available */\n\tif ( ! TYPE_HASZ(pts->dims) ) return lwgeom_pointarray_length2d(pts);\n\n\tfor (i=0; i<pts->npoints-1;i++)\n\t{\n\t\tgetPoint3dz_p(pts, i, &frm);\n\t\tgetPoint3dz_p(pts, i+1, &to);\n\t\tdist += sqrt( ( (frm.x - to.x)*(frm.x - to.x) )  +\n\t\t\t\t((frm.y - to.y)*(frm.y - to.y) ) +\n\t\t\t\t((frm.z - to.z)*(frm.z - to.z) ) );\n\t}\n\n\treturn dist;\n}\n\n/*\n * This should be rewritten to make use of the curve itself.\n */\ndouble\nlwgeom_curvepolygon_area(LWCURVEPOLY *curvepoly)\n{\n        LWPOLY *poly = (LWPOLY *)lwgeom_segmentize((LWGEOM *)curvepoly, 32);\n        return lwgeom_polygon_area(poly);\n}\n\n/*\n * Find the area of the outer ring - sum (area of inner rings).\n * Could use a more numerically stable calculator...\n */\ndouble\nlwgeom_polygon_area(LWPOLY *poly)\n{\n\tdouble poly_area=0.0;\n\tint i;\n\tPOINT2D p1;\n\tPOINT2D p2;\n\n\tLWDEBUGF(2, \"in lwgeom_polygon_area (%d rings)\", poly->nrings);\n\n\tfor (i=0; i<poly->nrings; i++)\n\t{\n\t\tint j;\n\t\tPOINTARRAY *ring = poly->rings[i];\n\t\tdouble ringarea = 0.0;\n\n\t\tLWDEBUGF(4, \" rings %d has %d points\", i, ring->npoints);\n\n\t\tfor (j=0; j<ring->npoints-1; j++)\n    \t\t{\n\t\t\tgetPoint2d_p(ring, j, &p1);\n\t\t\tgetPoint2d_p(ring, j+1, &p2);\n\t\t\tringarea += ( p1.x * p2.y ) - ( p1.y * p2.x );\n\t\t}\n\n\t\tringarea  /= 2.0;\n\n\t\tLWDEBUGF(4, \" ring 1 has area %lf\",ringarea);\n\n\t\tringarea  = fabs(ringarea);\n\t\tif (i != 0)\t/*outer */\n\t\t\tringarea  = -1.0*ringarea ; /* its a hole */\n\n\t\tpoly_area += ringarea;\n\t}\n\n\treturn poly_area;\n}\n\n/*\n * Compute the sum of polygon rings length.\n * Could use a more numerically stable calculator...\n */\ndouble lwgeom_polygon_perimeter(LWPOLY *poly)\n{\n\tdouble result=0.0;\n\tint i;\n\n\tLWDEBUGF(2, \"in lwgeom_polygon_perimeter (%d rings)\", poly->nrings);\n\n\tfor (i=0; i<poly->nrings; i++)\n\t\tresult += lwgeom_pointarray_length(poly->rings[i]);\n\n\treturn result;\n}\n\n/*\n * Compute the sum of polygon rings length (forcing 2d computation).\n * Could use a more numerically stable calculator...\n */\ndouble lwgeom_polygon_perimeter2d(LWPOLY *poly)\n{\n\tdouble result=0.0;\n\tint i;\n\n\tLWDEBUGF(2, \"in lwgeom_polygon_perimeter (%d rings)\", poly->nrings);\n\n\tfor (i=0; i<poly->nrings; i++)\n\t\tresult += lwgeom_pointarray_length2d(poly->rings[i]);\n\n\treturn result;\n}\n\ndouble\nlwgeom_mindistance2d_recursive(uchar *lw1, uchar *lw2)\n{\n  return lwgeom_mindistance2d_recursive_tolerance( lw1, lw2, 0.0 );\n}\n\ndouble\nlwgeom_mindistance2d_recursive_tolerance(uchar *lw1, uchar *lw2, double tolerance)\n{\n\tLWGEOM_INSPECTED *in1, *in2;\n\tint i, j;\n\tdouble mindist = -1;\n\n\tin1 = lwgeom_inspect(lw1);\n\tin2 = lwgeom_inspect(lw2);\n\n\tfor (i=0; i<in1->ngeometries; i++)\n\t{\n\t\tuchar *g1 = lwgeom_getsubgeometry_inspected(in1, i);\n\t\tint t1 = lwgeom_getType(g1[0]);\n\t\tdouble dist=tolerance;\n\n\t\t/* it's a multitype... recurse */\n\t\tif ( lwgeom_contains_subgeoms(t1) )\n\t\t{\n\t\t\tdist = lwgeom_mindistance2d_recursive_tolerance(g1, lw2, tolerance);\n\t\t\tif ( dist <= tolerance ) return tolerance; /* can't be closer */\n\t\t\tif ( mindist == -1 ) mindist = dist;\n\t\t\telse mindist = LW_MIN(dist, mindist);\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (j=0; j<in2->ngeometries; j++)\n\t\t{\n\t\t\tuchar *g2 = lwgeom_getsubgeometry_inspected(in2, j);\n\t\t\tint t2 = lwgeom_getType(g2[0]);\n\n\t\t\tif  ( t1 == POINTTYPE )\n\t\t\t{\n\t\t\t\tif  ( t2 == POINTTYPE )\n\t\t\t\t{\n\t\t\t\t\tdist = distance2d_point_point(\n\t\t\t\t\t\tlwpoint_deserialize(g1),\n\t\t\t\t\t\tlwpoint_deserialize(g2)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse if  ( t2 == LINETYPE )\n\t\t\t\t{\n\t\t\t\t\tdist = distance2d_point_line(\n\t\t\t\t\t\tlwpoint_deserialize(g1),\n\t\t\t\t\t\tlwline_deserialize(g2)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse if  ( t2 == POLYGONTYPE )\n\t\t\t\t{\n\t\t\t\t\tdist = distance2d_point_poly(\n\t\t\t\t\t\tlwpoint_deserialize(g1),\n\t\t\t\t\t\tlwpoly_deserialize(g2)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tlwerror(\"Unsupported geometry type: %s\", lwgeom_typename(t2));\n\t\t\t\t}\t\n\t\t\t}\n\t\t\telse if ( t1 == LINETYPE )\n\t\t\t{\n\t\t\t\tif ( t2 == POINTTYPE )\n\t\t\t\t{\n\t\t\t\t\tdist = distance2d_point_line(\n\t\t\t\t\t\tlwpoint_deserialize(g2),\n\t\t\t\t\t\tlwline_deserialize(g1)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse if ( t2 == LINETYPE )\n\t\t\t\t{\n\t\t\t\t\tdist = distance2d_line_line(\n\t\t\t\t\t\tlwline_deserialize(g1),\n\t\t\t\t\t\tlwline_deserialize(g2)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse if ( t2 == POLYGONTYPE )\n\t\t\t\t{\n\t\t\t\t\tdist = distance2d_line_poly(\n\t\t\t\t\t\tlwline_deserialize(g1),\n\t\t\t\t\t\tlwpoly_deserialize(g2)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tlwerror(\"Unsupported geometry type: %s\", lwgeom_typename(t2));\n\t\t\t\t}\t\n\t\t\t}\n\t\t\telse if ( t1 == POLYGONTYPE )\n\t\t\t{\n\t\t\t\tif ( t2 == POLYGONTYPE )\n\t\t\t\t{\n\t\t\t\t\tdist = distance2d_poly_poly(\n\t\t\t\t\t\tlwpoly_deserialize(g2),\n\t\t\t\t\t\tlwpoly_deserialize(g1)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse if ( t2 == POINTTYPE )\n\t\t\t\t{\n\t\t\t\t\tdist = distance2d_point_poly(\n\t\t\t\t\t\tlwpoint_deserialize(g2),\n\t\t\t\t\t\tlwpoly_deserialize(g1)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse if ( t2 == LINETYPE )\n\t\t\t\t{\n\t\t\t\t\tdist = distance2d_line_poly(\n\t\t\t\t\t\tlwline_deserialize(g2),\n\t\t\t\t\t\tlwpoly_deserialize(g1)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tlwerror(\"Unsupported geometry type: %s\", lwgeom_typename(t2));\n\t\t\t\t}\t\n\t\t\t}\n\t\t\telse if (lwgeom_contains_subgeoms(t1)) /* it's a multitype... recurse */\n\t\t\t{\n\t\t\t\tdist = lwgeom_mindistance2d_recursive_tolerance(g1, g2, tolerance);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlwerror(\"Unsupported geometry type: %s\", lwgeom_typename(t1));\n\t\t\t}\n\n\t\t\tif (mindist == -1 ) mindist = dist;\n\t\t\telse mindist = LW_MIN(dist, mindist);\n\n\t\t\tLWDEBUGF(3, \"dist %d-%d: %f - mindist: %f\",\n\t\t\t\ti, j, dist, mindist);\n\n\n\t\t\tif (mindist <= tolerance) return tolerance; /* can't be closer */\n\n\t\t}\n\n\t}\n\n\tif (mindist<0) mindist = 0; \n\n\treturn mindist;\n}\n\n\n\nint\nlwgeom_pt_inside_circle(POINT2D *p, double cx, double cy, double rad)\n{\n\tPOINT2D center;\n\n\tcenter.x = cx;\n\tcenter.y = cy;\n\n\tif ( distance2d_pt_pt(p, &center) < rad ) return 1;\n\telse return 0;\n\n}\n\n/*\n * Compute the azimuth of segment AB in radians.\n * Return 0 on exception (same point), 1 otherwise.\n */\nint\nazimuth_pt_pt(POINT2D *A, POINT2D *B, double *d)\n{\n\tif ( A->x == B->x )\n\t{\n\t\tif ( A->y < B->y ) *d=0.0;\n\t\telse if ( A->y > B->y ) *d=M_PI; \n\t\telse return 0;\n\t\treturn 1;\n\t}\n\n\tif ( A->y == B->y )\n\t{\n\t\tif ( A->x < B->x ) *d=M_PI/2; \n\t\telse if ( A->x > B->x ) *d=M_PI+(M_PI/2);\n\t\telse return 0;\n\t\treturn 1;\n\t}\n\n\tif ( A->x < B->x )\n\t{\n\t\tif ( A->y < B->y )\n\t\t{\n\t\t\t*d=atan(fabs(A->x - B->x) / fabs(A->y - B->y) );\n\t\t}\n\t\telse /* ( A->y > B->y )  - equality case handled above */\n\t\t{\n\t\t\t*d=atan(fabs(A->y - B->y) / fabs(A->x - B->x) )\n\t\t\t\t+ (M_PI/2);\n\t\t}\n\t}\n\n\telse /* ( A->x > B->x ) - equality case handled above */\n\t{\n\t\tif ( A->y > B->y )\n\t\t{\n\t\t\t*d=atan(fabs(A->x - B->x) / fabs(A->y - B->y) )\n\t\t\t\t+ M_PI;\n\t\t}\n\t\telse /* ( A->y < B->y )  - equality case handled above */\n\t\t{\n\t\t\t*d=atan(fabs(A->y - B->y) / fabs(A->x - B->x) )\n\t\t\t\t+ (M_PI+(M_PI/2));\n\t\t}\n\t}\n\n\treturn 1;\n}\n\n"
  },
  {
    "path": "src/liblwgeom/postgis_config.h",
    "content": "/* postgis_config.h.  Generated from postgis_config.h.in by configure.  */\n/* postgis_config.h.in.  Generated from configure.ac by autoheader.  */\n\n/* Define to 1 if you have the <dlfcn.h> header file. */\n#define HAVE_DLFCN_H 1\n\n/* Defined if libiconv headers and library are present */\n#define HAVE_ICONV 0\n\n/* Define to 1 if you have the <inttypes.h> header file. */\n#define HAVE_INTTYPES_H 1\n\n/* Define to 1 if you have the `geos_c' library (-lgeos_c). */\n#define HAVE_LIBGEOS_C 1\n\n/* Define to 1 if you have the `pq' library (-lpq). */\n#define HAVE_LIBPQ 0\n\n/* Define to 1 if you have the `proj' library (-lproj). */\n#define HAVE_LIBPROJ 0\n\n/* Define to 1 if you have the <memory.h> header file. */\n#define HAVE_MEMORY_H 1\n\n/* Define to 1 if you have the <stdint.h> header file. */\n#define HAVE_STDINT_H 1\n\n/* Define to 1 if you have the <stdlib.h> header file. */\n#define HAVE_STDLIB_H 1\n\n/* Define to 1 if you have the <strings.h> header file. */\n#define HAVE_STRINGS_H 1\n\n/* Define to 1 if you have the <string.h> header file. */\n#define HAVE_STRING_H 1\n\n/* Define to 1 if you have the <sys/stat.h> header file. */\n#define HAVE_SYS_STAT_H 1\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#define HAVE_SYS_TYPES_H 1\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#define HAVE_UNISTD_H 1\n\n/* Enable caching of bounding box within geometries */\n#define POSTGIS_AUTOCACHE_BBOX 0\n\n/* PostGIS build date */\n#define POSTGIS_BUILD_DATE \"2009-03-09 15:11:36\"\n\n/* PostGIS library debug level (0=disabled) */\n#define POSTGIS_DEBUG_LEVEL 0\n\n/* GEOS library version */\n#define POSTGIS_GEOS_VERSION 30\n\n/* PostGIS library version */\n#define POSTGIS_LIB_VERSION \"1.4.0SVN\"\n\n/* PostGIS major version */\n#define POSTGIS_MAJOR_VERSION \"1\"\n\n/* PostGIS micro version */\n#define POSTGIS_MICRO_VERSION \"0SVN\"\n\n/* PostGIS minor version */\n#define POSTGIS_MINOR_VERSION \"4\"\n\n/* PostgreSQL server version */\n#define POSTGIS_PGSQL_VERSION 83\n\n/* Enable GEOS profiling (0=disabled) */\n#define POSTGIS_PROFILE 0\n\n/* PROJ library version */\n#define POSTGIS_PROJ_VERSION 46\n\n/* PostGIS scripts version */\n#define POSTGIS_SCRIPTS_VERSION \"1.4.0SVN\"\n\n/* Enable use of ANALYZE statistics */\n#define POSTGIS_USE_STATS 1\n\n/* PostGIS version */\n#define POSTGIS_VERSION \"1.4 USE_GEOS=1 USE_PROJ=1 USE_STATS=1\"\n\n/* Define to 1 if you have the ANSI C header files. */\n#define STDC_HEADERS 1\n\n/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a\n   `char[]'. */\n#define YYTEXT_POINTER 1\n"
  },
  {
    "path": "src/liblwgeom/ptarray.c",
    "content": "/**********************************************************************\n * $Id: ptarray.c 3639 2009-02-04 00:28:37Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2006 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************/\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"liblwgeom.h\"\n\n\nPOINTARRAY *\nptarray_construct(char hasz, char hasm, unsigned int npoints)\n{\n\tuchar dims = 0;\n\tsize_t size; \n\tuchar *ptlist;\n\tPOINTARRAY *pa;\n\t\n\tTYPE_SETZM(dims, hasz?1:0, hasm?1:0);\n\tsize = TYPE_NDIMS(dims)*npoints*sizeof(double);\n\n\tptlist = (uchar *)lwalloc(size);\n\tpa = lwalloc(sizeof(POINTARRAY));\n\tpa->dims = dims;\n\tpa->serialized_pointlist = ptlist;\n\tpa->npoints = npoints;\n\n\treturn pa;\n\n}\n\nvoid ptarray_free(POINTARRAY *pa)\n{\n\t/* TODO \n\t*  Turn this on after retrofitting all calls to lwfree_ in /lwgeom \n\tif( pa->serialized_pointlist )\n\t\tlwfree(pa->serialized_pointlist);\n  */\n  \n\tlwfree(pa);\n}\n\nvoid\nptarray_reverse(POINTARRAY *pa)\n{\n\tPOINT4D pbuf;\n\tuint32 i;\n\tint ptsize = pointArray_ptsize(pa);\n\tint last = pa->npoints-1;\n\tint mid = last/2;\n\n\tfor (i=0; i<=mid; i++)\n\t{\n\t\tuchar *from, *to;\n\t\tfrom = getPoint_internal(pa, i);\n\t\tto = getPoint_internal(pa, (last-i));\n\t\tmemcpy((uchar *)&pbuf, to, ptsize);\n\t\tmemcpy(to, from, ptsize);\n\t\tmemcpy(from, (uchar *)&pbuf, ptsize);\n\t}\n\n}\n\n/*\n * calculate the 2d bounding box of a set of points\n * write result to the provided BOX2DFLOAT4\n * Return 0 if bounding box is NULL (empty geom)\n */\nint\nptarray_compute_box2d_p(const POINTARRAY *pa, BOX2DFLOAT4 *result)\n{\n\tint t;\n\tPOINT2D pt;\n\tBOX3D box;\n\n\tif (pa->npoints == 0) return 0;\n\n\tgetPoint2d_p(pa, 0, &pt);\n\n\tbox.xmin = pt.x;\n\tbox.xmax = pt.x;\n\tbox.ymin = pt.y;\n\tbox.ymax = pt.y;\n\n\tfor (t=1; t<pa->npoints; t++)\n\t{\n\t\tgetPoint2d_p(pa, t, &pt);\n\t\tif (pt.x < box.xmin) box.xmin = pt.x;\n\t\tif (pt.y < box.ymin) box.ymin = pt.y;\n\t\tif (pt.x > box.xmax) box.xmax = pt.x;\n\t\tif (pt.y > box.ymax) box.ymax = pt.y;\n\t}\n\n\tbox3d_to_box2df_p(&box, result);\n\n\treturn 1;\n}\n\n/*\n * Calculate the 2d bounding box of a set of points.\n * Return allocated BOX2DFLOAT4 or NULL (for empty array).\n */\nBOX2DFLOAT4 *\nptarray_compute_box2d(const POINTARRAY *pa)\n{\n\tint t;\n\tPOINT2D pt;\n\tBOX2DFLOAT4 *result;\n\n\tif (pa->npoints == 0) return NULL;\n\n\tresult = lwalloc(sizeof(BOX2DFLOAT4));\n\n\tgetPoint2d_p(pa, 0, &pt);\n\n\tresult->xmin = pt.x;\n\tresult->xmax = pt.x;\n\tresult->ymin = pt.y;\n\tresult->ymax = pt.y;\n\n\tfor (t=1;t<pa->npoints;t++)\n\t{\n\t\tgetPoint2d_p(pa, t, &pt);\n\t\tif (pt.x < result->xmin) result->xmin = pt.x;\n\t\tif (pt.y < result->ymin) result->ymin = pt.y;\n\t\tif (pt.x > result->xmax) result->xmax = pt.x;\n\t\tif (pt.y > result->ymax) result->ymax = pt.y;\n\t}\n\n\treturn result;\n}\n\n/*\n * Returns a modified POINTARRAY so that no segment is \n * longer then the given distance (computed using 2d).\n * Every input point is kept.\n * Z and M values for added points (if needed) are set to 0.\n */\nPOINTARRAY *\nptarray_segmentize2d(POINTARRAY *ipa, double dist)\n{\n\tdouble\tsegdist;\n\tPOINT4D\tp1, p2;\n\tvoid *ip, *op;\n\tPOINT4D pbuf;\n\tPOINTARRAY *opa;\n\tint maxpoints = ipa->npoints;\n\tint ptsize = pointArray_ptsize(ipa);\n\tint ipoff=0; /* input point offset */\n\n\tpbuf.x = pbuf.y = pbuf.z = pbuf.m = 0;\n\n\t/* Initial storage */\n\topa = (POINTARRAY *)lwalloc(ptsize * maxpoints);\n\topa->dims = ipa->dims;\n\topa->npoints = 0;\n\topa->serialized_pointlist = (uchar *)lwalloc(maxpoints*ptsize);\n\n\t/* Add first point */\n\topa->npoints++;\n\tgetPoint4d_p(ipa, ipoff, &p1);\n\top = getPoint_internal(opa, opa->npoints-1);\n\tmemcpy(op, &p1, ptsize); \n\tipoff++;\n\n\twhile (ipoff<ipa->npoints)\n\t{\n\t\t/*\n\t\t * We use these pointers to avoid\n\t\t * \"strict-aliasing rules break\" warning raised\n\t\t * by gcc (3.3 and up).\n\t\t *\n\t\t * It looks that casting a variable address (also\n\t\t * referred to as \"type-punned pointer\")\n\t\t * breaks those \"strict\" rules.\n\t\t *\n\t\t */\n\t\tPOINT4D *p1ptr=&p1, *p2ptr=&p2;\n\n\t\tgetPoint4d_p(ipa, ipoff, &p2);\n\n\t\tsegdist = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);\n\n\t\tif (segdist > dist) /* add an intermediate point */\n\t\t{\n\t\t\tpbuf.x = p1.x + (p2.x-p1.x)/segdist * dist;\n\t\t\tpbuf.y = p1.y + (p2.y-p1.y)/segdist * dist;\n\t\t\t/* might also compute z and m if available... */\n\t\t\tip = &pbuf;\n\t\t\tmemcpy(&p1, ip, ptsize);\n\t\t}\n\t\telse /* copy second point */\n\t\t{\n\t\t\tip = &p2;\n\t\t\tp1 = p2;\n\t\t\tipoff++;\n\t\t}\n\n\t\t/* Add point */\n\t\tif ( ++(opa->npoints) > maxpoints ) {\n\t\t\tmaxpoints *= 1.5;\n\t\t\topa->serialized_pointlist = (uchar *)lwrealloc(\n\t\t\t\topa->serialized_pointlist,\n\t\t\t\tmaxpoints*ptsize\n\t\t\t);\n\t\t}\n\t\top = getPoint_internal(opa, opa->npoints-1);\n\t\tmemcpy(op, ip, ptsize); \n\t}\n\n\treturn opa;\n}\n\nchar\nptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2)\n{\n\tunsigned int i;\n\tsize_t ptsize;\n\n\tif ( TYPE_GETZM(pa1->dims) != TYPE_GETZM(pa2->dims) ) return 0;\n\n\tif ( pa1->npoints != pa2->npoints ) return 0;\n\n\tptsize = pointArray_ptsize(pa1);\n\n\tfor (i=0; i<pa1->npoints; i++)\n\t{\n\t\tif ( memcmp(getPoint_internal(pa1, i), getPoint_internal(pa2, i), ptsize) )\n\t\t\treturn 0;\n\t}\n\n\treturn 1;\n}\n\n/*\n * Add a point in a pointarray.\n * 'where' is the offset (starting at 0)\n * if 'where' == -1 append is required.\n */\nPOINTARRAY *\nptarray_addPoint(POINTARRAY *pa, uchar *p, size_t pdims, unsigned int where)\n{\n\tPOINTARRAY *ret;\n\tPOINT4D pbuf;\n\tsize_t ptsize = pointArray_ptsize(pa);\n\n\tLWDEBUGF(3, \"pa %x p %x size %d where %d\",\n\t\tpa, p, pdims, where);\n\n\tif ( pdims < 2 || pdims > 4 )\n\t{\n\t\tlwerror(\"ptarray_addPoint: point dimension out of range (%d)\",\n\t\t\tpdims);\n\t\treturn NULL;\n\t}\n\n\tif ( where > pa->npoints )\n\t{\n\t\tlwerror(\"ptarray_addPoint: offset out of range (%d)\",\n\t\t\twhere);\n\t\treturn NULL;\n\t}\n\n\tLWDEBUG(3, \"called with a %dD point\");\n\t\n\tpbuf.x = pbuf.y = pbuf.z = pbuf.m = 0.0;\n\tmemcpy((uchar *)&pbuf, p, pdims*sizeof(double));\n\n\tLWDEBUG(3, \"initialized point buffer\");\n\n\tret = ptarray_construct(TYPE_HASZ(pa->dims),\n\t\tTYPE_HASM(pa->dims), pa->npoints+1);\n\t\n\tif ( where == -1 ) where = pa->npoints;\n\n\tif ( where )\n\t{\n\t\tmemcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*where);\n\t}\n\n\tmemcpy(getPoint_internal(ret, where), (uchar *)&pbuf, ptsize);\n\n\tif ( where+1 != ret->npoints )\n\t{\n\t\tmemcpy(getPoint_internal(ret, where+1),\n\t\t\tgetPoint_internal(pa, where),\n\t\t\tptsize*(pa->npoints-where));\n\t}\n\n\treturn ret;\n}\n\n/*\n * Remove a point from a pointarray.\n * 'which' is the offset (starting at 0)\n * Returned pointarray is newly allocated\n */\nPOINTARRAY *\nptarray_removePoint(POINTARRAY *pa, unsigned int which)\n{\n\tPOINTARRAY *ret;\n\tsize_t ptsize = pointArray_ptsize(pa);\n\n\tLWDEBUGF(3, \"pa %x which %d\", pa, which);\n\n#if PARANOIA_LEVEL > 0\n\tif ( which > pa->npoints-1 )\n\t{\n\t\tlwerror(\"ptarray_removePoint: offset (%d) out of range (%d..%d)\",\n\t\t\twhich, 0, pa->npoints-1);\n\t\treturn NULL;\n\t}\n\n\tif ( pa->npoints < 3 )\n\t{\n\t\tlwerror(\"ptarray_removePointe: can't remove a point from a 2-vertex POINTARRAY\");\n\t}\n#endif\n\n\tret = ptarray_construct(TYPE_HASZ(pa->dims),\n\t\tTYPE_HASM(pa->dims), pa->npoints-1);\n\t\n\t/* copy initial part */\n\tif ( which )\n\t{\n\t\tmemcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*which);\n\t}\n\n\t/* copy final part */\n\tif ( which < pa->npoints-1 )\n\t{\n\t\tmemcpy(getPoint_internal(ret, which), getPoint_internal(pa, which+1),\n\t\t\tptsize*(pa->npoints-which-1));\n\t}\n\n\treturn ret;\n}\n\n/* \n * Clone a pointarray \n */\nPOINTARRAY *\nptarray_clone(const POINTARRAY *in)\n{\n\tPOINTARRAY *out = lwalloc(sizeof(POINTARRAY));\n\tsize_t size;\n\n        LWDEBUG(3, \"ptarray_clone called.\");\n\n\tout->dims = in->dims;\n\tout->npoints = in->npoints;\n\n\tsize = in->npoints*sizeof(double)*TYPE_NDIMS(in->dims);\n\tout->serialized_pointlist = lwalloc(size);\n\tmemcpy(out->serialized_pointlist, in->serialized_pointlist, size);\n\n\treturn out;\n}\n\nint\nptarray_isclosed2d(const POINTARRAY *in)\n{\n\tif ( memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), sizeof(POINT2D)) ) return 0;\n\treturn 1;\n}\n\n/*\n * calculate the BOX3D bounding box of a set of points\n * returns a lwalloced BOX3D, or NULL on empty array.\n * zmin/zmax values are set to NO_Z_VALUE if not available.\n */\nBOX3D *\nptarray_compute_box3d(const POINTARRAY *pa)\n{\n\tBOX3D *result = lwalloc(sizeof(BOX3D));\n\n\tif ( ! ptarray_compute_box3d_p(pa, result) )\n\t{\n\t\tlwfree(result);\n\t\treturn NULL;\n\t}\n\n\treturn result;\n}\n\n/*\n * calculate the BOX3D bounding box of a set of points\n * zmin/zmax values are set to NO_Z_VALUE if not available.\n * write result to the provided BOX3D\n * Return 0 if bounding box is NULL (empty geom)\n */\nint\nptarray_compute_box3d_p(const POINTARRAY *pa, BOX3D *result)\n{\n\tint t;\n\tPOINT3DZ pt;\n\n\tLWDEBUGF(3, \"ptarray_compute_box3d call (array has %d points)\", pa->npoints);\n\t\n\tif (pa->npoints == 0) return 0;\n\n\tgetPoint3dz_p(pa, 0, &pt);\n\n\tLWDEBUG(3, \"got point 0\");\n\n\tresult->xmin = pt.x;\n\tresult->xmax = pt.x;\n\tresult->ymin = pt.y;\n\tresult->ymax = pt.y;\n\n\tif ( TYPE_HASZ(pa->dims) ) {\n\t\tresult->zmin = pt.z;\n\t\tresult->zmax = pt.z;\n\t} else {\n\t\tresult->zmin = NO_Z_VALUE;\n\t\tresult->zmax = NO_Z_VALUE;\n\t}\n\n\tLWDEBUGF(3, \"scanning other %d points\", pa->npoints);\n\n\tfor (t=1; t<pa->npoints; t++)\n\t{\n\t\tgetPoint3dz_p(pa,t,&pt);\n\t\tif (pt.x < result->xmin) result->xmin = pt.x;\n\t\tif (pt.y < result->ymin) result->ymin = pt.y;\n\t\tif (pt.x > result->xmax) result->xmax = pt.x;\n\t\tif (pt.y > result->ymax) result->ymax = pt.y;\n\n\t\tif ( TYPE_HASZ(pa->dims) ) {\n\t\t\tif (pt.z > result->zmax) result->zmax = pt.z;\n\t\t\tif (pt.z < result->zmin) result->zmin = pt.z;\n\t\t}\n\t}\n\n\tLWDEBUG(3, \"returning box\");\n\n\treturn 1;\n}\n\n/*\n * TODO: implement point interpolation\n */\nPOINTARRAY *\nptarray_substring(POINTARRAY *ipa, double from, double to)\n{\n\tDYNPTARRAY *dpa;\n\tPOINTARRAY *opa;\n\tPOINT4D pt;\n\tPOINT4D p1, p2;\n\tPOINT4D *p1ptr=&p1; /* don't break strict-aliasing rule */\n\tPOINT4D *p2ptr=&p2;\n\tint nsegs, i;\n\tdouble length, slength, tlength;\n\tint state = 0; /* 0=before, 1=inside */\n\n\t/*\n\t * Create a dynamic pointarray with an initial capacity\n\t * equal to full copy of input points\n\t */\n\tdpa = dynptarray_create(ipa->npoints, ipa->dims);\n\n\t/* Compute total line length */\n\tlength = lwgeom_pointarray_length2d(ipa);\n\n\n\tLWDEBUGF(3, \"Total length: %g\", length);\n\n\n\t/* Get 'from' and 'to' lengths */\n\tfrom = length*from;\n\tto = length*to;\n\n\n\tLWDEBUGF(3, \"From/To: %g/%g\", from, to);\n\n\n\ttlength = 0;\n\tgetPoint4d_p(ipa, 0, &p1);\n\tnsegs = ipa->npoints - 1;\n\tfor( i = 0; i < nsegs; i++ )\n\t{\n\t\tdouble dseg;\n\n\t\tgetPoint4d_p(ipa, i+1, &p2);\n\n\n\t\tLWDEBUGF(3 ,\"Segment %d: (%g,%g,%g,%g)-(%g,%g,%g,%g)\",\n\t\t\ti, p1.x, p1.y, p1.z, p1.m, p2.x, p2.y, p2.z, p2.m);\n\n\n\t\t/* Find the length of this segment */\n\t\tslength = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);\n\n\t\t/*\n\t\t * We are before requested start.\n\t\t */\n\t\tif ( state == 0 ) /* before */\n\t\t{\n\n\t\t\tLWDEBUG(3, \" Before start\");\n\n\t\t\t/*\n\t\t\t * Didn't reach the 'from' point,\n\t\t\t * nothing to do\n\t\t\t */\n\t\t\tif ( from > tlength + slength ) goto END;\n\n\t\t\telse if ( from == tlength + slength )\n\t\t\t{\n\n\t\t\t\tLWDEBUG(3, \"  Second point is our start\");\n\n\t\t\t\t/*\n\t\t\t\t * Second point is our start\n\t\t\t\t */\n\t\t\t\tdynptarray_addPoint4d(dpa, &p2, 1);\n\t\t\t\tstate=1; /* we're inside now */\n\t\t\t\tgoto END;\n\t\t\t}\n\n\t\t\telse if ( from == tlength )\n\t\t\t{\n\n\t\t\t\tLWDEBUG(3, \"  First point is our start\");\n\n\t\t\t\t/*\n\t\t\t\t * First point is our start\n\t\t\t\t */\n\t\t\t\tdynptarray_addPoint4d(dpa, &p1, 1);\n\n\t\t\t\t/*\n\t\t\t\t * We're inside now, but will check\n\t\t\t\t * 'to' point as well\n\t\t\t\t */\n\t\t\t\tstate=1;\n\t\t\t}\n\n\t\t\telse  /* tlength < from < tlength+slength */\n\t\t\t{\n\n\t\t\t\tLWDEBUG(3, \"  Seg contains first point\");\n\n\t\t\t\t/*\n\t\t\t\t * Our start is between first and\n\t\t\t\t * second point\n\t\t\t\t */\n\t\t\t\tdseg = (from - tlength) / slength;\n\t\t\t\tinterpolate_point4d(&p1, &p2, &pt, dseg);\n\n\t\t\t\tdynptarray_addPoint4d(dpa, &pt, 1);\n\n\t\t\t\t/*\n\t\t\t\t * We're inside now, but will check\n\t\t\t\t * 'to' point as well\n\t\t\t\t */\n\t\t\t\tstate=1;\n\t\t\t}\n\t\t}\n\n\t\tif ( state == 1 ) /* inside */\n\t\t{\n\n\t\t\tLWDEBUG(3, \" Inside\");\n\n\t\t\t/*\n\t\t\t * Didn't reach the 'end' point,\n\t\t\t * just copy second point\n\t\t\t */\n\t\t\tif ( to > tlength + slength ) \n\t\t\t{\n\t\t\t\tdynptarray_addPoint4d(dpa, &p2, 0);\n\t\t\t\tgoto END;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * 'to' point is our second point.\n\t\t\t */\n\t\t\telse if ( to == tlength + slength )\n\t\t\t{\n\n\t\t\t\tLWDEBUG(3, \" Second point is our end\");\n\n\t\t\t\tdynptarray_addPoint4d(dpa, &p2, 0);\n\t\t\t\tbreak; /* substring complete */\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * 'to' point is our first point.\n\t\t\t * (should only happen if 'to' is 0)\n\t\t\t */\n\t\t\telse if ( to == tlength )\n\t\t\t{\n\n\t\t\t\tLWDEBUG(3, \" First point is our end\");\n\n\t\t\t\tdynptarray_addPoint4d(dpa, &p1, 0);\n\n\t\t\t\tbreak; /* substring complete */\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * 'to' point falls on this segment\n\t\t\t * Interpolate and break.\n\t\t\t */\n\t\t\telse if ( to < tlength + slength )\n\t\t\t{\n\n\t\t\t\tLWDEBUG(3, \" Seg contains our end\");\n\n\t\t\t\tdseg = (to - tlength) / slength;\n\t\t\t\tinterpolate_point4d(&p1, &p2, &pt, dseg);\n\n\t\t\t\tdynptarray_addPoint4d(dpa, &pt, 0);\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\telse\n\t\t\t{\n\t\t\t\tLWDEBUG(3, \"Unhandled case\");\n\t\t\t}\n\t\t}\n\n\n\t\tEND:\n\n\t\ttlength += slength;\n\t\tmemcpy(&p1, &p2, sizeof(POINT4D));\n\t}\n\n\t/* Get constructed pointarray and release memory associated\n\t * with the dynamic pointarray\n\t */\n\topa = dpa->pa;\n\tlwfree(dpa);\n\n\tLWDEBUGF(3, \"Out of loop, ptarray has %d points\", opa->npoints);\n\n\treturn opa;\n}\n\n/*\n * Write into the *ret argument coordinates of the closes point on\n * the given segment to the reference input point.\n */\nvoid\nclosest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret)\n{\n\tdouble r;\n\n\tif (  ( A->x == B->x) && (A->y == B->y) )\n\t{\n\t\t*ret = *A;\n\t\treturn;\n\t}\n\n\t/*\n\t * We use comp.graphics.algorithms Frequently Asked Questions method\n\t *\n\t * (1)           AC dot AB\n\t *           r = ----------\n\t *                ||AB||^2\n\t *\tr has the following meaning:\n\t *\tr=0 P = A\n\t *\tr=1 P = B\n\t *\tr<0 P is on the backward extension of AB\n\t *\tr>1 P is on the forward extension of AB\n\t *\t0<r<1 P is interior to AB\n\t *\t\n\t */\n\tr = ( (p->x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );\n\n\tif (r<0) {\n\t\t*ret = *A; return;\n\t}\n\tif (r>1) {\n\t\t*ret = *B;\n\t\treturn;\n\t}\n\n\tret->x = A->x + ( (B->x - A->x) * r );\n\tret->y = A->y + ( (B->y - A->y) * r );\n}\n\n/*\n * Given a point, returns the location of closest point on pointarray\n */\ndouble\nptarray_locate_point(POINTARRAY *pa, POINT2D *p)\n{\n\tdouble mindist=-1;\n\tdouble tlen, plen;\n\tint t, seg=-1;\n\tPOINT2D\tstart, end;\n\tPOINT2D proj;\n\n\tgetPoint2d_p(pa, 0, &start);\n\tfor (t=1; t<pa->npoints; t++)\n\t{\n\t\tdouble dist;\n\t\tgetPoint2d_p(pa, t, &end);\n\t\tdist = distance2d_pt_seg(p, &start, &end);\n\n\t\tif (t==1 || dist < mindist ) {\n\t\t\tmindist = dist;\n\t\t\tseg=t-1;\n\t\t}\n\n\t\tif ( mindist == 0 ) break;\n\n\t\tstart = end;\n\t}\n\n\tLWDEBUGF(3, \"Closest segment: %d\", seg);\n\n\t/*\n\t * If mindist is not 0 we need to project the \n\t * point on the closest segment.\n\t */\n\tif ( mindist > 0 )\n\t{\n\t\tgetPoint2d_p(pa, seg, &start);\n\t\tgetPoint2d_p(pa, seg+1, &end);\n\t\tclosest_point_on_segment(p, &start, &end, &proj);\n\t} else {\n\t\tproj = *p;\n\t}\n\n\tLWDEBUGF(3, \"Closest point on segment: %g,%g\", proj.x, proj.y);\n\n\ttlen = lwgeom_pointarray_length2d(pa);\n\n\tLWDEBUGF(3, \"tlen %g\", tlen);\n\n\tplen=0;\n\tgetPoint2d_p(pa, 0, &start);\n\tfor (t=0; t<seg; t++, start=end)\n\t{\n\t\tgetPoint2d_p(pa, t+1, &end);\n\t\tplen += distance2d_pt_pt(&start, &end);\n\n\t\tLWDEBUGF(4, \"Segment %d made plen %g\", t, plen);\n\t}\n\n\tplen+=distance2d_pt_pt(&proj, &start);\n\n\tLWDEBUGF(3, \"plen %g, tlen %g\", plen, tlen);\n\tLWDEBUGF(3, \"mindist: %g\", mindist);\n\n\treturn plen/tlen;\n}\n\n/*\n * Longitude shift for a pointarray.\n *  Y remains the same\n *  X is converted:\n *\t from -180..180 to 0..360\n *\t from 0..360 to -180..180\n *  X < 0 becomes X + 360\n *  X > 180 becomes X - 360\n */\nvoid\nptarray_longitude_shift(POINTARRAY *pa)\n{\n\tint i;\n\tdouble x;\n\n\tfor (i=0; i<pa->npoints; i++) {\n\t\tmemcpy(&x, getPoint_internal(pa, i), sizeof(double));\n\t\tif ( x < 0 ) x+= 360;\n\t\telse if ( x > 180 ) x -= 360;\n\t\tmemcpy(getPoint_internal(pa, i), &x, sizeof(double));\n\t}\n}\n\nDYNPTARRAY *\ndynptarray_create(size_t initial_capacity, int dims)\n{\n\tDYNPTARRAY *ret=lwalloc(sizeof(DYNPTARRAY));\n\n        LWDEBUGF(3, \"dynptarray_create called, dims=%d.\", dims);\n\n\tif ( initial_capacity < 1 ) initial_capacity=1;\n\n\tret->pa=lwalloc(sizeof(POINTARRAY));\n\tret->pa->dims=dims;\n\tret->ptsize=pointArray_ptsize(ret->pa);\n\tret->capacity=initial_capacity;\n\tret->pa->serialized_pointlist=lwalloc(ret->ptsize*ret->capacity);\n\tret->pa->npoints=0;\n\n\treturn ret;\n}\n\n/*\n * Add a POINT4D to the dynamic pointarray.\n *\n * The dynamic pointarray may be of any dimension, only\n * accepted dimensions will be copied.\n *\n * If allow_duplicates is set to 0 (false) a check\n * is performed to see if last point in array is equal to the\n * provided one. NOTE that the check is 4d based, with missing\n * ordinates in the pointarray set to NO_Z_VALUE and NO_M_VALUE\n * respectively.\n */\nint\ndynptarray_addPoint4d(DYNPTARRAY *dpa, POINT4D *p4d, int allow_duplicates)\n{\n\tPOINTARRAY *pa=dpa->pa;\n\tPOINT4D tmp;\n\n        LWDEBUG(3, \"dynptarray_addPoint4d called.\");\n\n\tif ( ! allow_duplicates && pa->npoints > 0 )\n\t{\n\t\tgetPoint4d_p(pa, pa->npoints-1, &tmp);\n\n\t\t/*\n\t\t * return 0 and do nothing else if previous point in list is\n\t\t * equal to this one  (4D equality)\n\t\t */\n\t\tif (tmp.x == p4d->x && tmp.y == p4d->y && tmp.z == p4d->z && tmp.m == p4d->m) return 0;\n\t}\n\n\t++pa->npoints;\n\tif ( pa->npoints > dpa->capacity )\n\t{\n\t\tdpa->capacity*=2;\n\t\tpa->serialized_pointlist = lwrealloc(\n\t\t\tpa->serialized_pointlist,\n\t\t\tdpa->capacity*dpa->ptsize);\n\t}\n\n\tsetPoint4d(pa, pa->npoints-1, p4d);\n\n\treturn 1;\n}\n\n"
  },
  {
    "path": "src/liblwgeom/vsprintf.c",
    "content": "/* Like vsprintf but provides a pointer to malloc'd storage, which must\n   be freed by the caller.\n   Copyright (C) 1994, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.\n\nThis program is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation; either version 2, or (at your option)\nany later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */\n\n#ifdef HAVE_CONFIG_H\n# include <config.h>\n#endif\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n\n#if __STDC__\n# include <stdarg.h>\n#else\n# include <varargs.h>\n#endif\n\n#include <math.h>\n\n#ifdef TEST\nint global_total_width;\n#endif\n\n\nint lw_vasprintf (char **result, const char *format, va_list args);\nint lw_asprintf\n#if __STDC__\n     (char **result, const char *format, ...);\n#else\n     (result, va_alist);\n     char **result;\n     va_dcl\n#endif\n\n\nstatic int\nint_vasprintf (result, format, args)\n     char **result;\n     const char *format;\n     va_list *args;\n{\n  const char *p = format;\n  /* Add one to make sure that it is never zero, which might cause malloc\n     to return NULL.  */\n  int total_width = strlen (format) + 1;\n  va_list ap;\n\n  memcpy (&ap, args, sizeof (va_list));\n\n  while (*p != '\\0')\n    {\n      if (*p++ == '%')\n\t{\n\t  while (strchr (\"-+ #0\", *p))\n\t    ++p;\n\t  if (*p == '*')\n\t    {\n\t      ++p;\n\t      total_width += abs (va_arg (ap, int));\n\t    }\n\t  else\n\t    total_width += strtoul (p, (char **) &p, 10);\n\t  if (*p == '.')\n\t    {\n\t      ++p;\n\t      if (*p == '*')\n\t\t{\n\t\t  ++p;\n\t\t  total_width += abs (va_arg (ap, int));\n\t\t}\n\t      else\n\t\ttotal_width += strtoul (p, (char **) &p, 10);\n\t    }\n\t  while (strchr (\"hlLjtz\", *p))\n\t    ++p;\n\t  /* Should be big enough for any format specifier except %s\n\t     and floats.  */\n\t  total_width += 30;\n\t  switch (*p)\n\t    {\n\t    case 'd':\n\t    case 'i':\n\t    case 'o':\n\t    case 'u':\n\t    case 'x':\n\t    case 'X':\n\t    case 'c':\n\t      (void) va_arg (ap, int);\n\t      break;\n\t    case 'f':\n\t      {\n\t\tdouble arg = va_arg (ap, double);\n\t\tif (arg >= 1.0 || arg <= -1.0)\n\t\t  /* Since an ieee double can have an exponent of 307, we'll\n\t\t     make the buffer wide enough to cover the gross case. */\n\t\t  total_width += 307;\n\t      }\n\t      break;\n\t    case 'e':\n\t    case 'E':\n\t    case 'g':\n\t    case 'G':\n\t      (void) va_arg (ap, double);\n\t      break;\n\t    case 's':\n\t      total_width += strlen (va_arg (ap, char *));\n\t      break;\n\t    case 'p':\n\t    case 'n':\n\t      (void) va_arg (ap, char *);\n\t      break;\n\t    }\n\t  p++;\n\t}\n    }\n#ifdef TEST\n  global_total_width = total_width;\n#endif\n  *result = malloc (total_width);\n  if (*result != NULL)\n    return vsprintf (*result, format, *args);\n  else\n    return 0;\n}\n\nint\nlw_vasprintf (result, format, args)\n     char **result;\n     const char *format;\n     va_list args;\n{\n  va_list temp;\n\n  /* Use va_copy for compatibility with both 32 and 64 bit args */\n  __va_copy(temp, args);\n\n  return int_vasprintf (result, format, &temp);\n}\n\nint\nlw_asprintf\n#if __STDC__\n     (char **result, const char *format, ...)\n#else\n     (result, va_alist)\n     char **result;\n     va_dcl\n#endif\n{\n  va_list args;\n  int done;\n\n#if __STDC__\n  va_start (args, format);\n#else\n  char *format;\n  va_start (args);\n  format = va_arg (args, char *);\n#endif\n  done = lw_vasprintf (result, format, args);\n  va_end (args);\n\n  return done;\n} \n"
  },
  {
    "path": "src/liblwgeom/wktparse.h",
    "content": "/*\n * Written by Ralph Mason ralph.mason<at>telogis.com\n *\n * Copyright Telogis 2004\n * www.telogis.com\n *\n */\n\n#ifndef _WKTPARSE_H\n#define _WKTPARSE_H\n\n#include <stdlib.h>\n\n\n#ifndef _LIBLWGEOM_H\ntypedef unsigned char uchar;\n\ntypedef struct serialized_lwgeom {\n    uchar *lwgeom;\n    int size;\n} SERIALIZED_LWGEOM;\n\ntypedef struct struct_lwgeom_parser_result\n{\n\tconst char *wkinput;\n        SERIALIZED_LWGEOM *serialized_lwgeom;\n        int size;\n        const char *message;\n        int errlocation;\n} LWGEOM_PARSER_RESULT;\n\ntypedef struct struct_lwgeom_unparser_result\n{\n\tuchar *serialized_lwgeom;\n        char *wkoutput;\n        int size;\n\tconst char *message;\n        int errlocation;\n} LWGEOM_UNPARSER_RESULT;\n#endif\ntypedef void* (*allocator)(size_t size);\ntypedef void  (*freeor)(void* mem);\ntypedef void  (*report_error)(const char* string, ...);\n\n/*typedef unsigned long int4;*/\n\n/* How much memory is allocated at a time(bytes) for tuples */\n#define ALLOC_CHUNKS 8192\n\n/* to shrink ints less than 0x7f to 1 byte */\n/* #define SHRINK_INTS */\n\n#define\tPOINTTYPE\t1\n#define\tLINETYPE\t2\n#define\tPOLYGONTYPE\t3\n#define\tMULTIPOINTTYPE\t4\n#define\tMULTILINETYPE\t5\n#define\tMULTIPOLYGONTYPE\t6\n#define\tCOLLECTIONTYPE\t7\n\n/* Extended lwgeom integer types */\n#define POINTTYPEI    10\n#define LINETYPEI     11\n#define POLYGONTYPEI  12\n\n#define CIRCSTRINGTYPE       8\n#define COMPOUNDTYPE    9\n#define CURVEPOLYTYPE   13\n#define MULTICURVETYPE          14\n#define MULTISURFACETYPE        15\n\nextern int srid;\n\n/*\n\n   These functions are used by  the\n   generated parser and are not meant\n   for public use\n\n*/\n\nvoid set_srid(double srid);\nvoid alloc_lwgeom(int srid);\n\nvoid alloc_point_2d(double x,double y);\nvoid alloc_point_3d(double x,double y,double z);\nvoid alloc_point_4d(double x,double y,double z,double m);\n\nvoid alloc_point(void);\nvoid alloc_linestring(void);\nvoid alloc_linestring_closed(void);\nvoid alloc_circularstring(void);\nvoid alloc_circularstring_closed(void);\nvoid alloc_polygon(void);\nvoid alloc_compoundcurve(void);\nvoid alloc_curvepolygon(void);\nvoid alloc_multipoint(void);\nvoid alloc_multilinestring(void);\nvoid alloc_multicurve(void);\nvoid alloc_multipolygon(void);\nvoid alloc_multisurface(void);\nvoid alloc_geomertycollection(void);\nvoid alloc_empty();\nvoid alloc_counter(void);\n\n\nvoid pop(void);\nvoid popc(void);\n\nvoid alloc_wkb(const char* parser);\n\n/*\n\tUse these functions to parse and unparse lwgeoms\n\tYou are responsible for freeing the returned memory.\n*/\n\nint parse_lwg(LWGEOM_PARSER_RESULT *lwg_parser_result, const char* wkt, int flags, allocator allocfunc,report_error errfunc);\nint parse_lwgi(LWGEOM_PARSER_RESULT *lwg_parser_result, const char* wkt, int flags, allocator allocfunc,report_error errfunc);\nint unparse_WKT(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar* serialized, allocator alloc, freeor free, int flags);\nint unparse_WKB(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar* serialized, allocator alloc, freeor free, int flags, char endian, uchar hexform);\nint lwg_parse_yyparse(void);\nint lwg_parse_yyerror(char* s);\nvoid lwg_parse_yynotice(char* s);\n\n\n#endif /* _WKTPARSE_H */\n"
  },
  {
    "path": "src/liblwgeom/wktparse.lex",
    "content": "/*\n * Written by Ralph Mason ralph.mason<at>telogis.com\n *\n * Copyright Telogis 2004\n * www.telogis.com\n *\n */\n\n%x vals_ok\n%{\n#include \"wktparse.tab.h\"\n#include <unistd.h>\n#include <stdlib.h> /* need stdlib for atof() definition */\n\nvoid init_parser(const char *src);\nvoid close_parser(void);\nint lwg_parse_yywrap(void);\nint lwg_parse_yylex(void);\n\nstatic YY_BUFFER_STATE buf_state;\n   void init_parser(const char *src) { BEGIN(0);buf_state = lwg_parse_yy_scan_string(src); }\n   void close_parser() { lwg_parse_yy_delete_buffer(buf_state); }\n   int lwg_parse_yywrap(void){ return 1; }\n\n/* Macro to keep track of the current parse position */\n#define UPDATE_YYLLOC() (lwg_parse_yylloc.last_column += yyleng)\n\n%}\n\n%%\n\n<vals_ok>[-|\\+]?[0-9]+(\\.[0-9]+)?([Ee](\\+|-)?[0-9]+)? { lwg_parse_yylval.value=atof(lwg_parse_yytext); UPDATE_YYLLOC(); return VALUE; }\n<vals_ok>[-|\\+]?(\\.[0-9]+)([Ee](\\+|-)?[0-9]+)? { lwg_parse_yylval.value=atof(lwg_parse_yytext); UPDATE_YYLLOC(); return VALUE; }\n\n<INITIAL>00[0-9A-F]* {  lwg_parse_yylval.wkb=lwg_parse_yytext; return WKB;}\n<INITIAL>01[0-9A-F]* {  lwg_parse_yylval.wkb=lwg_parse_yytext; return WKB;}\n\n<*>POINT \t{ UPDATE_YYLLOC(); return POINT; }\n<*>POINTM \t{ UPDATE_YYLLOC(); return POINTM; }\n<*>LINESTRING { UPDATE_YYLLOC(); return LINESTRING; }\n<*>LINESTRINGM { UPDATE_YYLLOC(); return LINESTRINGM; }\n<*>CIRCULARSTRING { UPDATE_YYLLOC(); return CIRCULARSTRING; }\n<*>CIRCULARSTRINGM { UPDATE_YYLLOC(); return CIRCULARSTRINGM; }\n<*>POLYGON { UPDATE_YYLLOC(); return POLYGON; }\n<*>POLYGONM { UPDATE_YYLLOC(); return POLYGONM; }\n<*>COMPOUNDCURVE { UPDATE_YYLLOC(); return COMPOUNDCURVE; }\n<*>COMPOUNDCURVEM { UPDATE_YYLLOC(); return COMPOUNDCURVEM; }\n<*>CURVEPOLYGON { UPDATE_YYLLOC(); return CURVEPOLYGON; }\n<*>CURVEPOLYGONM { UPDATE_YYLLOC(); return CURVEPOLYGONM; }\n<*>MULTIPOINT { UPDATE_YYLLOC(); return MULTIPOINT; }\n<*>MULTIPOINTM { UPDATE_YYLLOC(); return MULTIPOINTM; }\n<*>MULTILINESTRING { UPDATE_YYLLOC(); return MULTILINESTRING; }\n<*>MULTILINESTRINGM { UPDATE_YYLLOC(); return MULTILINESTRINGM; }\n<*>MULTICURVE { UPDATE_YYLLOC(); return MULTICURVE; }\n<*>MULTICURVEM { UPDATE_YYLLOC(); return MULTICURVEM; }\n<*>MULTIPOLYGON { UPDATE_YYLLOC(); return MULTIPOLYGON; }\n<*>MULTIPOLYGONM { UPDATE_YYLLOC(); return MULTIPOLYGONM; }\n<*>MULTISURFACE { UPDATE_YYLLOC(); return MULTISURFACE; }\n<*>MULTISURFACEM { UPDATE_YYLLOC(); return MULTISURFACEM; }\n<*>GEOMETRYCOLLECTION { UPDATE_YYLLOC(); return GEOMETRYCOLLECTION; }\n<*>GEOMETRYCOLLECTIONM { UPDATE_YYLLOC(); return GEOMETRYCOLLECTIONM; }\n<*>SRID { BEGIN(vals_ok); UPDATE_YYLLOC(); return SRID; }\n<*>EMPTY { UPDATE_YYLLOC(); return EMPTY; }\n\n<*>\\(\t{ BEGIN(vals_ok); UPDATE_YYLLOC(); return LPAREN; }\n<*>\\)\t{ UPDATE_YYLLOC(); return RPAREN; }\n<*>,\t{ UPDATE_YYLLOC(); return COMMA ; }\n<*>=\t{ UPDATE_YYLLOC(); return EQUALS ; }\n<*>;\t{ BEGIN(0); UPDATE_YYLLOC(); return SEMICOLON; }\n<*>[ \\t\\n\\r]+ /*eat whitespace*/ { UPDATE_YYLLOC(); }\n<*>.\t{ return lwg_parse_yytext[0]; }\n\n%%\n\n"
  },
  {
    "path": "src/liblwgeom/wktparse.tab.c",
    "content": "/* A Bison parser, made by GNU Bison 2.3.  */\n\n/* Skeleton implementation for Bison's Yacc-like parsers in C\n\n   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006\n   Free Software Foundation, Inc.\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2, or (at your option)\n   any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 51 Franklin Street, Fifth Floor,\n   Boston, MA 02110-1301, USA.  */\n\n/* As a special exception, you may create a larger work that contains\n   part or all of the Bison parser skeleton and distribute that work\n   under terms of your choice, so long as that work isn't itself a\n   parser generator using the skeleton or a modified version thereof\n   as a parser skeleton.  Alternatively, if you modify or redistribute\n   the parser skeleton itself, you may (at your option) remove this\n   special exception, which will cause the skeleton and the resulting\n   Bison output files to be licensed under the GNU General Public\n   License without this special exception.\n\n   This special exception was added by the Free Software Foundation in\n   version 2.2 of Bison.  */\n\n/* C LALR(1) parser skeleton written by Richard Stallman, by\n   simplifying the original so-called \"semantic\" parser.  */\n\n/* All symbols defined below should begin with yy or YY, to avoid\n   infringing on user name space.  This should be done even for local\n   variables, as they might otherwise be expanded by user macros.\n   There are some unavoidable exceptions within include files to\n   define necessary library symbols; they are noted \"INFRINGES ON\n   USER NAME SPACE\" below.  */\n\n/* Identify Bison output.  */\n#define YYBISON 1\n\n/* Bison version.  */\n#define YYBISON_VERSION \"2.3\"\n\n/* Skeleton name.  */\n#define YYSKELETON_NAME \"yacc.c\"\n\n/* Pure parsers.  */\n#define YYPURE 0\n\n/* Using locations.  */\n#define YYLSP_NEEDED 1\n\n/* Substitute the variable and function names.  */\n#define yyparse lwg_parse_yyparse\n#define yylex   lwg_parse_yylex\n#define yyerror lwg_parse_yyerror\n#define yylval  lwg_parse_yylval\n#define yychar  lwg_parse_yychar\n#define yydebug lwg_parse_yydebug\n#define yynerrs lwg_parse_yynerrs\n#define yylloc lwg_parse_yylloc\n\n/* Tokens.  */\n#ifndef YYTOKENTYPE\n# define YYTOKENTYPE\n   /* Put the tokens into the symbol table, so that GDB and other debuggers\n      know about them.  */\n   enum yytokentype {\n     POINT = 258,\n     LINESTRING = 259,\n     POLYGON = 260,\n     MULTIPOINT = 261,\n     MULTILINESTRING = 262,\n     MULTIPOLYGON = 263,\n     GEOMETRYCOLLECTION = 264,\n     CIRCULARSTRING = 265,\n     COMPOUNDCURVE = 266,\n     CURVEPOLYGON = 267,\n     MULTICURVE = 268,\n     MULTISURFACE = 269,\n     POINTM = 270,\n     LINESTRINGM = 271,\n     POLYGONM = 272,\n     MULTIPOINTM = 273,\n     MULTILINESTRINGM = 274,\n     MULTIPOLYGONM = 275,\n     GEOMETRYCOLLECTIONM = 276,\n     CIRCULARSTRINGM = 277,\n     COMPOUNDCURVEM = 278,\n     CURVEPOLYGONM = 279,\n     MULTICURVEM = 280,\n     MULTISURFACEM = 281,\n     SRID = 282,\n     EMPTY = 283,\n     VALUE = 284,\n     LPAREN = 285,\n     RPAREN = 286,\n     COMMA = 287,\n     EQUALS = 288,\n     SEMICOLON = 289,\n     WKB = 290\n   };\n#endif\n/* Tokens.  */\n#define POINT 258\n#define LINESTRING 259\n#define POLYGON 260\n#define MULTIPOINT 261\n#define MULTILINESTRING 262\n#define MULTIPOLYGON 263\n#define GEOMETRYCOLLECTION 264\n#define CIRCULARSTRING 265\n#define COMPOUNDCURVE 266\n#define CURVEPOLYGON 267\n#define MULTICURVE 268\n#define MULTISURFACE 269\n#define POINTM 270\n#define LINESTRINGM 271\n#define POLYGONM 272\n#define MULTIPOINTM 273\n#define MULTILINESTRINGM 274\n#define MULTIPOLYGONM 275\n#define GEOMETRYCOLLECTIONM 276\n#define CIRCULARSTRINGM 277\n#define COMPOUNDCURVEM 278\n#define CURVEPOLYGONM 279\n#define MULTICURVEM 280\n#define MULTISURFACEM 281\n#define SRID 282\n#define EMPTY 283\n#define VALUE 284\n#define LPAREN 285\n#define RPAREN 286\n#define COMMA 287\n#define EQUALS 288\n#define SEMICOLON 289\n#define WKB 290\n\n\n\n\n/* Copy the first part of user declarations.  */\n#line 9 \"wktparse.y\"\n\n#include \"wktparse.h\"\n#include <unistd.h>\n#include <stdio.h>\n\nvoid set_zm(char z, char m);\nint lwg_parse_yylex(void);\n\n\n/* Enabling traces.  */\n#ifndef YYDEBUG\n# define YYDEBUG 0\n#endif\n\n/* Enabling verbose error messages.  */\n#ifdef YYERROR_VERBOSE\n# undef YYERROR_VERBOSE\n# define YYERROR_VERBOSE 1\n#else\n# define YYERROR_VERBOSE 0\n#endif\n\n/* Enabling the token table.  */\n#ifndef YYTOKEN_TABLE\n# define YYTOKEN_TABLE 0\n#endif\n\n#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED\ntypedef union YYSTYPE\n#line 22 \"wktparse.y\"\n{\n\tdouble value;\n\tconst char* wkb;\n}\n/* Line 187 of yacc.c.  */\n#line 188 \"y.tab.c\"\n\tYYSTYPE;\n# define yystype YYSTYPE /* obsolescent; will be withdrawn */\n# define YYSTYPE_IS_DECLARED 1\n# define YYSTYPE_IS_TRIVIAL 1\n#endif\n\n#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED\ntypedef struct YYLTYPE\n{\n  int first_line;\n  int first_column;\n  int last_line;\n  int last_column;\n} YYLTYPE;\n# define yyltype YYLTYPE /* obsolescent; will be withdrawn */\n# define YYLTYPE_IS_DECLARED 1\n# define YYLTYPE_IS_TRIVIAL 1\n#endif\n\n\n/* Copy the second part of user declarations.  */\n\n\n/* Line 216 of yacc.c.  */\n#line 213 \"y.tab.c\"\n\n#ifdef short\n# undef short\n#endif\n\n#ifdef YYTYPE_UINT8\ntypedef YYTYPE_UINT8 yytype_uint8;\n#else\ntypedef unsigned char yytype_uint8;\n#endif\n\n#ifdef YYTYPE_INT8\ntypedef YYTYPE_INT8 yytype_int8;\n#elif (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\ntypedef signed char yytype_int8;\n#else\ntypedef short int yytype_int8;\n#endif\n\n#ifdef YYTYPE_UINT16\ntypedef YYTYPE_UINT16 yytype_uint16;\n#else\ntypedef unsigned short int yytype_uint16;\n#endif\n\n#ifdef YYTYPE_INT16\ntypedef YYTYPE_INT16 yytype_int16;\n#else\ntypedef short int yytype_int16;\n#endif\n\n#ifndef YYSIZE_T\n# ifdef __SIZE_TYPE__\n#  define YYSIZE_T __SIZE_TYPE__\n# elif defined size_t\n#  define YYSIZE_T size_t\n# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\n#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */\n#  define YYSIZE_T size_t\n# else\n#  define YYSIZE_T unsigned int\n# endif\n#endif\n\n#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)\n\n#ifndef YY_\n# if YYENABLE_NLS\n#  if ENABLE_NLS\n#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */\n#   define YY_(msgid) dgettext (\"bison-runtime\", msgid)\n#  endif\n# endif\n# ifndef YY_\n#  define YY_(msgid) msgid\n# endif\n#endif\n\n/* Suppress unused-variable warnings by \"using\" E.  */\n#if ! defined lint || defined __GNUC__\n# define YYUSE(e) ((void) (e))\n#else\n# define YYUSE(e) /* empty */\n#endif\n\n/* Identity function, used to suppress warnings about constant conditions.  */\n#ifndef lint\n# define YYID(n) (n)\n#else\n#if (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nstatic int\nYYID (int i)\n#else\nstatic int\nYYID (i)\n    int i;\n#endif\n{\n  return i;\n}\n#endif\n\n#if ! defined yyoverflow || YYERROR_VERBOSE\n\n/* The parser invokes alloca or malloc; define the necessary symbols.  */\n\n# ifdef YYSTACK_USE_ALLOCA\n#  if YYSTACK_USE_ALLOCA\n#   ifdef __GNUC__\n#    define YYSTACK_ALLOC __builtin_alloca\n#   elif defined __BUILTIN_VA_ARG_INCR\n#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */\n#   elif defined _AIX\n#    define YYSTACK_ALLOC __alloca\n#   elif defined _MSC_VER\n#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */\n#    define alloca _alloca\n#   else\n#    define YYSTACK_ALLOC alloca\n#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\n#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */\n#     ifndef _STDLIB_H\n#      define _STDLIB_H 1\n#     endif\n#    endif\n#   endif\n#  endif\n# endif\n\n# ifdef YYSTACK_ALLOC\n   /* Pacify GCC's `empty if-body' warning.  */\n#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))\n#  ifndef YYSTACK_ALLOC_MAXIMUM\n    /* The OS might guarantee only one guard page at the bottom of the stack,\n       and a page size can be as small as 4096 bytes.  So we cannot safely\n       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number\n       to allow for a few compiler-allocated temporary stack slots.  */\n#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */\n#  endif\n# else\n#  define YYSTACK_ALLOC YYMALLOC\n#  define YYSTACK_FREE YYFREE\n#  ifndef YYSTACK_ALLOC_MAXIMUM\n#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM\n#  endif\n#  if (defined __cplusplus && ! defined _STDLIB_H \\\n       && ! ((defined YYMALLOC || defined malloc) \\\n\t     && (defined YYFREE || defined free)))\n#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */\n#   ifndef _STDLIB_H\n#    define _STDLIB_H 1\n#   endif\n#  endif\n#  ifndef YYMALLOC\n#   define YYMALLOC malloc\n#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nvoid *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */\n#   endif\n#  endif\n#  ifndef YYFREE\n#   define YYFREE free\n#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nvoid free (void *); /* INFRINGES ON USER NAME SPACE */\n#   endif\n#  endif\n# endif\n#endif /* ! defined yyoverflow || YYERROR_VERBOSE */\n\n\n#if (! defined yyoverflow \\\n     && (! defined __cplusplus \\\n\t || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \\\n\t     && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))\n\n/* A type that is properly aligned for any stack member.  */\nunion yyalloc\n{\n  yytype_int16 yyss;\n  YYSTYPE yyvs;\n    YYLTYPE yyls;\n};\n\n/* The size of the maximum gap between one aligned stack and the next.  */\n# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)\n\n/* The size of an array large to enough to hold all stacks, each with\n   N elements.  */\n# define YYSTACK_BYTES(N) \\\n     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \\\n      + 2 * YYSTACK_GAP_MAXIMUM)\n\n/* Copy COUNT objects from FROM to TO.  The source and destination do\n   not overlap.  */\n# ifndef YYCOPY\n#  if defined __GNUC__ && 1 < __GNUC__\n#   define YYCOPY(To, From, Count) \\\n      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))\n#  else\n#   define YYCOPY(To, From, Count)\t\t\\\n      do\t\t\t\t\t\\\n\t{\t\t\t\t\t\\\n\t  YYSIZE_T yyi;\t\t\t\t\\\n\t  for (yyi = 0; yyi < (Count); yyi++)\t\\\n\t    (To)[yyi] = (From)[yyi];\t\t\\\n\t}\t\t\t\t\t\\\n      while (YYID (0))\n#  endif\n# endif\n\n/* Relocate STACK from its old location to the new one.  The\n   local variables YYSIZE and YYSTACKSIZE give the old and new number of\n   elements in the stack, and YYPTR gives the new location of the\n   stack.  Advance YYPTR to a properly aligned location for the next\n   stack.  */\n# define YYSTACK_RELOCATE(Stack)\t\t\t\t\t\\\n    do\t\t\t\t\t\t\t\t\t\\\n      {\t\t\t\t\t\t\t\t\t\\\n\tYYSIZE_T yynewbytes;\t\t\t\t\t\t\\\n\tYYCOPY (&yyptr->Stack, Stack, yysize);\t\t\t\t\\\n\tStack = &yyptr->Stack;\t\t\t\t\t\t\\\n\tyynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \\\n\tyyptr += yynewbytes / sizeof (*yyptr);\t\t\t\t\\\n      }\t\t\t\t\t\t\t\t\t\\\n    while (YYID (0))\n\n#endif\n\n/* YYFINAL -- State number of the termination state.  */\n#define YYFINAL  6\n/* YYLAST -- Last index in YYTABLE.  */\n#define YYLAST   180\n\n/* YYNTOKENS -- Number of terminals.  */\n#define YYNTOKENS  36\n/* YYNNTS -- Number of nonterminals.  */\n#define YYNNTS  107\n/* YYNRULES -- Number of rules.  */\n#define YYNRULES  169\n/* YYNRULES -- Number of states.  */\n#define YYNSTATES  237\n\n/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */\n#define YYUNDEFTOK  2\n#define YYMAXUTOK   290\n\n#define YYTRANSLATE(YYX)\t\t\t\t\t\t\\\n  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)\n\n/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */\nstatic const yytype_uint8 yytranslate[] =\n{\n       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,\n       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,\n      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,\n      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,\n      35\n};\n\n#if YYDEBUG\n/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in\n   YYRHS.  */\nstatic const yytype_uint16 yyprhs[] =\n{\n       0,     0,     3,     4,     9,    10,    13,    15,    17,    19,\n      21,    23,    25,    27,    29,    31,    33,    35,    37,    39,\n      43,    45,    48,    49,    53,    55,    57,    58,    61,    62,\n      65,    69,    70,    74,    75,    79,    81,    82,    87,    89,\n      93,    95,    96,    99,   102,   103,   107,   109,   111,   112,\n     115,   116,   119,   120,   123,   124,   129,   131,   135,   138,\n     139,   143,   146,   147,   151,   153,   155,   157,   159,   160,\n     163,   164,   167,   168,   171,   172,   177,   179,   183,   184,\n     188,   189,   193,   195,   196,   201,   203,   205,   209,   213,\n     214,   218,   219,   223,   225,   226,   231,   233,   237,   238,\n     242,   243,   247,   249,   250,   255,   257,   259,   263,   267,\n     270,   271,   275,   277,   279,   280,   283,   284,   287,   288,\n     293,   295,   299,   300,   304,   305,   309,   311,   312,   317,\n     319,   321,   325,   329,   330,   334,   335,   339,   341,   342,\n     347,   349,   353,   354,   358,   359,   363,   365,   366,   371,\n     373,   375,   379,   383,   384,   388,   389,   393,   395,   396,\n     401,   403,   405,   409,   411,   413,   415,   418,   422,   427\n};\n\n/* YYRHS -- A `-1'-separated list of the rules' RHS.  */\nstatic const yytype_int16 yyrhs[] =\n{\n      37,     0,    -1,    -1,    41,    34,    38,    40,    -1,    -1,\n      39,    40,    -1,    42,    -1,    43,    -1,    59,    -1,    71,\n      -1,   104,    -1,    86,    -1,   114,    -1,    51,    -1,    92,\n      -1,    98,    -1,   120,    -1,   126,    -1,   132,    -1,    27,\n      33,    29,    -1,    35,    -1,     3,    45,    -1,    -1,    15,\n      44,    45,    -1,    46,    -1,    48,    -1,    -1,    47,   142,\n      -1,    -1,    49,    50,    -1,    30,   138,    31,    -1,    -1,\n       6,    52,    54,    -1,    -1,    18,    53,    54,    -1,   142,\n      -1,    -1,    55,    30,    56,    31,    -1,    57,    -1,    56,\n      32,    57,    -1,    48,    -1,    -1,    58,   138,    -1,     4,\n      61,    -1,    -1,    16,    60,    61,    -1,    62,    -1,    64,\n      -1,    -1,    63,   142,    -1,    -1,    65,    68,    -1,    -1,\n      67,    68,    -1,    -1,    69,    30,    70,    31,    -1,   138,\n      -1,    70,    32,   138,    -1,    10,    75,    -1,    -1,    22,\n      72,    75,    -1,    10,    76,    -1,    -1,    22,    74,    76,\n      -1,    77,    -1,    79,    -1,    77,    -1,    81,    -1,    -1,\n      78,   142,    -1,    -1,    80,    83,    -1,    -1,    82,    83,\n      -1,    -1,    84,    30,    85,    31,    -1,   138,    -1,    85,\n      32,   138,    -1,    -1,    11,    87,    89,    -1,    -1,    23,\n      88,    89,    -1,   142,    -1,    -1,    90,    30,    91,    31,\n      -1,    64,    -1,    71,    -1,    91,    32,    64,    -1,    91,\n      32,    71,    -1,    -1,     7,    93,    95,    -1,    -1,    19,\n      94,    95,    -1,   142,    -1,    -1,    96,    30,    97,    31,\n      -1,    64,    -1,    97,    32,    64,    -1,    -1,    13,    99,\n     101,    -1,    -1,    25,   100,   101,    -1,   142,    -1,    -1,\n     102,    30,   103,    31,    -1,    64,    -1,    71,    -1,   103,\n      32,    64,    -1,   103,    32,    71,    -1,     5,   106,    -1,\n      -1,    17,   105,   106,    -1,   107,    -1,   109,    -1,    -1,\n     108,   142,    -1,    -1,   110,   111,    -1,    -1,   112,    30,\n     113,    31,    -1,    68,    -1,   113,    32,    68,    -1,    -1,\n      12,   115,   117,    -1,    -1,    24,   116,   117,    -1,   142,\n      -1,    -1,   118,    30,   119,    31,    -1,    66,    -1,    73,\n      -1,   119,    32,    66,    -1,   119,    32,    73,    -1,    -1,\n       8,   121,   123,    -1,    -1,    20,   122,   123,    -1,   142,\n      -1,    -1,   124,    30,   125,    31,    -1,   109,    -1,   125,\n      32,   109,    -1,    -1,    14,   127,   129,    -1,    -1,    26,\n     128,   129,    -1,   142,    -1,    -1,   130,    30,   131,    31,\n      -1,   109,    -1,   114,    -1,   131,    32,   109,    -1,   131,\n      32,   114,    -1,    -1,     9,   133,   135,    -1,    -1,    21,\n     134,   135,    -1,   142,    -1,    -1,   136,    30,   137,    31,\n      -1,   142,    -1,    40,    -1,   137,    32,    40,    -1,   139,\n      -1,   140,    -1,   141,    -1,    29,    29,    -1,    29,    29,\n      29,    -1,    29,    29,    29,    29,    -1,    28,    -1\n};\n\n/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */\nstatic const yytype_uint16 yyrline[] =\n{\n       0,    38,    38,    38,    40,    40,    43,    45,    47,    49,\n      51,    53,    55,    57,    59,    61,    63,    65,    67,    70,\n      73,    79,    81,    81,    84,    86,    89,    89,    92,    92,\n      95,   100,   100,   102,   102,   105,   107,   107,   110,   112,\n     115,   118,   118,   124,   126,   126,   129,   131,   134,   134,\n     137,   137,   140,   140,   143,   143,   146,   148,   153,   155,\n     155,   158,   160,   160,   163,   165,   168,   170,   173,   173,\n     176,   176,   179,   179,   182,   182,   185,   187,   192,   192,\n     194,   194,   197,   199,   199,   202,   204,   206,   208,   213,\n     213,   216,   216,   220,   222,   222,   225,   227,   232,   232,\n     235,   235,   239,   241,   241,   244,   246,   248,   250,   255,\n     257,   257,   260,   262,   265,   265,   268,   268,   271,   271,\n     274,   276,   281,   281,   283,   283,   287,   289,   289,   292,\n     294,   296,   298,   303,   303,   305,   305,   309,   311,   311,\n     314,   316,   321,   321,   323,   323,   327,   329,   329,   332,\n     334,   336,   338,   343,   343,   346,   346,   350,   352,   352,\n     356,   358,   360,   364,   366,   368,   371,   374,   377,   380\n};\n#endif\n\n#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE\n/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.\n   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */\nstatic const char *const yytname[] =\n{\n  \"$end\", \"error\", \"$undefined\", \"POINT\", \"LINESTRING\", \"POLYGON\",\n  \"MULTIPOINT\", \"MULTILINESTRING\", \"MULTIPOLYGON\", \"GEOMETRYCOLLECTION\",\n  \"CIRCULARSTRING\", \"COMPOUNDCURVE\", \"CURVEPOLYGON\", \"MULTICURVE\",\n  \"MULTISURFACE\", \"POINTM\", \"LINESTRINGM\", \"POLYGONM\", \"MULTIPOINTM\",\n  \"MULTILINESTRINGM\", \"MULTIPOLYGONM\", \"GEOMETRYCOLLECTIONM\",\n  \"CIRCULARSTRINGM\", \"COMPOUNDCURVEM\", \"CURVEPOLYGONM\", \"MULTICURVEM\",\n  \"MULTISURFACEM\", \"SRID\", \"EMPTY\", \"VALUE\", \"LPAREN\", \"RPAREN\", \"COMMA\",\n  \"EQUALS\", \"SEMICOLON\", \"WKB\", \"$accept\", \"geometry\", \"@1\", \"@2\",\n  \"geometry_int\", \"srid\", \"geom_wkb\", \"geom_point\", \"@3\", \"point\",\n  \"empty_point\", \"@4\", \"nonempty_point\", \"@5\", \"point_int\",\n  \"geom_multipoint\", \"@6\", \"@7\", \"multipoint\", \"@8\", \"multipoint_int\",\n  \"mpoint_element\", \"@9\", \"geom_linestring\", \"@10\", \"linestring\",\n  \"empty_linestring\", \"@11\", \"nonempty_linestring\", \"@12\",\n  \"nonempty_linestring_closed\", \"@13\", \"linestring_1\", \"@14\",\n  \"linestring_int\", \"geom_circularstring\", \"@15\",\n  \"geom_circularstring_closed\", \"@16\", \"circularstring\",\n  \"circularstring_closed\", \"empty_circularstring\", \"@17\",\n  \"nonempty_circularstring\", \"@18\", \"nonempty_circularstring_closed\",\n  \"@19\", \"circularstring_1\", \"@20\", \"circularstring_int\",\n  \"geom_compoundcurve\", \"@21\", \"@22\", \"compoundcurve\", \"@23\",\n  \"compoundcurve_int\", \"geom_multilinestring\", \"@24\", \"@25\",\n  \"multilinestring\", \"@26\", \"multilinestring_int\", \"geom_multicurve\",\n  \"@27\", \"@28\", \"multicurve\", \"@29\", \"multicurve_int\", \"geom_polygon\",\n  \"@30\", \"polygon\", \"empty_polygon\", \"@31\", \"nonempty_polygon\", \"@32\",\n  \"polygon_1\", \"@33\", \"polygon_int\", \"geom_curvepolygon\", \"@34\", \"@35\",\n  \"curvepolygon\", \"@36\", \"curvepolygon_int\", \"geom_multipolygon\", \"@37\",\n  \"@38\", \"multipolygon\", \"@39\", \"multipolygon_int\", \"geom_multisurface\",\n  \"@40\", \"@41\", \"multisurface\", \"@42\", \"multisurface_int\",\n  \"geom_geometrycollection\", \"@43\", \"@44\", \"geometrycollection\", \"@45\",\n  \"geometrycollection_int\", \"a_point\", \"point_2d\", \"point_3d\", \"point_4d\",\n  \"empty\", 0\n};\n#endif\n\n# ifdef YYPRINT\n/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to\n   token YYLEX-NUM.  */\nstatic const yytype_uint16 yytoknum[] =\n{\n       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,\n     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,\n     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,\n     285,   286,   287,   288,   289,   290\n};\n# endif\n\n/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */\nstatic const yytype_uint8 yyr1[] =\n{\n       0,    36,    38,    37,    39,    37,    40,    40,    40,    40,\n      40,    40,    40,    40,    40,    40,    40,    40,    40,    41,\n      42,    43,    44,    43,    45,    45,    47,    46,    49,    48,\n      50,    52,    51,    53,    51,    54,    55,    54,    56,    56,\n      57,    58,    57,    59,    60,    59,    61,    61,    63,    62,\n      65,    64,    67,    66,    69,    68,    70,    70,    71,    72,\n      71,    73,    74,    73,    75,    75,    76,    76,    78,    77,\n      80,    79,    82,    81,    84,    83,    85,    85,    87,    86,\n      88,    86,    89,    90,    89,    91,    91,    91,    91,    93,\n      92,    94,    92,    95,    96,    95,    97,    97,    99,    98,\n     100,    98,   101,   102,   101,   103,   103,   103,   103,   104,\n     105,   104,   106,   106,   108,   107,   110,   109,   112,   111,\n     113,   113,   115,   114,   116,   114,   117,   118,   117,   119,\n     119,   119,   119,   121,   120,   122,   120,   123,   124,   123,\n     125,   125,   127,   126,   128,   126,   129,   130,   129,   131,\n     131,   131,   131,   133,   132,   134,   132,   135,   136,   135,\n     137,   137,   137,   138,   138,   138,   139,   140,   141,   142\n};\n\n/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */\nstatic const yytype_uint8 yyr2[] =\n{\n       0,     2,     0,     4,     0,     2,     1,     1,     1,     1,\n       1,     1,     1,     1,     1,     1,     1,     1,     1,     3,\n       1,     2,     0,     3,     1,     1,     0,     2,     0,     2,\n       3,     0,     3,     0,     3,     1,     0,     4,     1,     3,\n       1,     0,     2,     2,     0,     3,     1,     1,     0,     2,\n       0,     2,     0,     2,     0,     4,     1,     3,     2,     0,\n       3,     2,     0,     3,     1,     1,     1,     1,     0,     2,\n       0,     2,     0,     2,     0,     4,     1,     3,     0,     3,\n       0,     3,     1,     0,     4,     1,     1,     3,     3,     0,\n       3,     0,     3,     1,     0,     4,     1,     3,     0,     3,\n       0,     3,     1,     0,     4,     1,     1,     3,     3,     2,\n       0,     3,     1,     1,     0,     2,     0,     2,     0,     4,\n       1,     3,     0,     3,     0,     3,     1,     0,     4,     1,\n       1,     3,     3,     0,     3,     0,     3,     1,     0,     4,\n       1,     3,     0,     3,     0,     3,     1,     0,     4,     1,\n       1,     3,     3,     0,     3,     0,     3,     1,     0,     4,\n       1,     1,     3,     1,     1,     1,     2,     3,     4,     1\n};\n\n/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state\n   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero\n   means the default is an error.  */\nstatic const yytype_uint8 yydefact[] =\n{\n       4,     0,     0,     0,     0,     0,     1,    26,    48,   114,\n      31,    89,   133,   153,    68,    78,   122,    98,   142,    22,\n      44,   110,    33,    91,   135,   155,    59,    80,   124,   100,\n     144,    20,     5,     6,     7,    13,     8,     9,    11,    14,\n      15,    10,    12,    16,    17,    18,     2,    19,    21,    24,\n       0,    25,     0,    43,    46,     0,    47,    54,   109,   112,\n       0,   113,   118,    36,    94,   138,   158,    58,    64,     0,\n      65,    74,    83,   127,   103,   147,    26,    48,   114,    36,\n      94,   138,   158,    68,    83,   127,   103,   147,     0,   169,\n      27,     0,    29,    49,    51,     0,   115,   117,     0,    32,\n       0,    35,    90,     0,    93,   134,     0,   137,   154,     0,\n     157,    69,    71,     0,    79,     0,    82,   123,     0,   126,\n      99,     0,   102,   143,     0,   146,    23,    45,   111,    34,\n      92,   136,   156,    60,    81,   125,   101,   145,     3,     0,\n       0,   163,   164,   165,     0,    54,    28,    50,   116,     0,\n       0,    50,    52,    50,   116,   166,    30,     0,    56,   120,\n       0,    40,     0,    38,     0,    96,     0,   140,     0,   161,\n       0,   160,     0,    76,    85,    86,     0,    68,    62,   129,\n      54,   130,     0,   105,   106,     0,   149,   150,     0,   167,\n      55,     0,   119,    54,    37,    28,    42,    95,    50,   139,\n     116,   159,     0,    75,     0,    84,    50,    61,    66,    67,\n      74,    68,    53,   128,    52,   104,    50,   148,   116,   168,\n      57,   121,    39,    97,   141,   162,    77,    87,    88,    73,\n      63,   131,   132,   107,   108,   151,   152\n};\n\n/* YYDEFGOTO[NTERM-NUM].  */\nstatic const yytype_int16 yydefgoto[] =\n{\n      -1,     2,    88,     3,    32,     4,    33,    34,    76,    48,\n      49,    50,    51,    52,    92,    35,    63,    79,    99,   100,\n     162,   163,   164,    36,    77,    53,    54,    55,    56,    57,\n     179,   180,    94,    95,   157,    37,    83,   181,   211,    67,\n     207,    68,    69,    70,    71,   209,   210,   112,   113,   172,\n      38,    72,    84,   114,   115,   176,    39,    64,    80,   102,\n     103,   166,    40,    74,    86,   120,   121,   185,    41,    78,\n      58,    59,    60,    61,    62,    97,    98,   160,    42,    73,\n      85,   117,   118,   182,    43,    65,    81,   105,   106,   168,\n      44,    75,    87,   123,   124,   188,    45,    66,    82,   108,\n     109,   170,   140,   141,   142,   143,   101\n};\n\n/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing\n   STATE-NUM.  */\n#define YYPACT_NINF -166\nstatic const yytype_int16 yypact[] =\n{\n     -17,   -14,    21,   145,    -7,     5,  -166,    29,    30,    40,\n    -166,  -166,  -166,  -166,    51,  -166,  -166,  -166,  -166,  -166,\n    -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,\n    -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,\n    -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,\n      23,  -166,    53,  -166,  -166,    23,  -166,  -166,  -166,  -166,\n      23,  -166,  -166,    23,    23,    23,    23,  -166,  -166,    23,\n    -166,  -166,    23,    23,    23,    23,    29,    30,    40,    23,\n      23,    23,    23,    51,    23,    23,    23,    23,   145,  -166,\n    -166,    55,  -166,  -166,  -166,    56,  -166,  -166,    57,  -166,\n      58,  -166,  -166,    59,  -166,  -166,    61,  -166,  -166,    62,\n    -166,  -166,  -166,    63,  -166,    64,  -166,  -166,    65,  -166,\n    -166,    66,  -166,  -166,    67,  -166,  -166,  -166,  -166,  -166,\n    -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,    70,\n      54,  -166,  -166,  -166,    55,  -166,    72,  -166,  -166,   112,\n      55,     8,    19,     8,    28,    73,  -166,   -18,  -166,  -166,\n      16,  -166,    18,  -166,    55,  -166,    24,  -166,    31,  -166,\n      33,  -166,    35,  -166,  -166,  -166,    42,    74,  -166,  -166,\n    -166,  -166,    44,  -166,  -166,    46,  -166,  -166,    48,    76,\n    -166,    55,  -166,  -166,  -166,    72,  -166,  -166,  -166,  -166,\n    -166,  -166,   145,  -166,    55,  -166,     8,  -166,  -166,  -166,\n    -166,    74,  -166,  -166,    19,  -166,     8,  -166,    28,  -166,\n    -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,  -166,\n    -166,  -166,  -166,  -166,  -166,  -166,  -166\n};\n\n/* YYPGOTO[NTERM-NUM].  */\nstatic const yytype_int16 yypgoto[] =\n{\n    -166,  -166,  -166,  -166,   -88,  -166,  -166,  -166,  -166,    27,\n    -166,  -166,  -142,  -166,  -166,  -166,  -166,  -166,    32,  -166,\n    -166,   -89,  -166,  -166,  -166,    36,  -166,  -166,  -108,  -166,\n    -107,  -166,  -136,  -166,  -166,  -148,  -166,  -105,  -166,    60,\n    -101,  -165,  -166,  -166,  -166,  -166,  -166,   -98,  -166,  -166,\n    -166,  -166,  -166,    88,  -166,  -166,  -166,  -166,  -166,    93,\n    -166,  -166,  -166,  -166,  -166,    89,  -166,  -166,  -166,  -166,\n      68,  -166,  -166,  -146,  -166,  -166,  -166,  -166,  -147,  -166,\n    -166,    91,  -166,  -166,  -166,  -166,  -166,    96,  -166,  -166,\n    -166,  -166,  -166,    52,  -166,  -166,  -166,  -166,  -166,    92,\n    -166,  -166,  -122,  -166,  -166,  -166,   -49\n};\n\n/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If\n   positive, shift that token.  If negative, reduce the rule which\n   number is the opposite.  If zero, do what YYDEFACT says.\n   If YYTABLE_NINF, syntax error.  */\n#define YYTABLE_NINF -117\nstatic const yytype_int16 yytable[] =\n{\n     138,    90,   167,   175,   161,   184,    93,   187,   186,   159,\n       1,    96,   208,   190,   191,   104,   107,   110,    14,     5,\n     111,     6,   158,   116,   119,   122,   125,    46,   173,   177,\n      26,   104,   107,   110,    47,   116,   119,   122,   125,   165,\n      16,   178,   196,   174,   212,   183,   208,   192,   193,   194,\n     195,    89,    28,   161,   224,   197,   198,   221,   228,   -28,\n     -50,   169,   199,   200,   201,   202,   203,   204,   234,   220,\n    -116,   236,   235,   205,   206,   213,   214,   215,   216,   217,\n     218,   -70,   226,    91,   139,   156,   144,   145,   146,   147,\n     223,   148,   149,   150,   151,   152,   153,   154,   227,   155,\n     171,   -41,   189,   126,   -72,   219,   222,   231,   233,   232,\n     230,   129,   229,   127,   225,     7,     8,     9,    10,    11,\n      12,    13,    14,    15,    16,    17,    18,    19,    20,    21,\n      22,    23,    24,    25,    26,    27,    28,    29,    30,   137,\n      89,     0,     0,   133,     0,     0,   128,    31,     7,     8,\n       9,    10,    11,    12,    13,    14,    15,    16,    17,    18,\n      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,\n      29,    30,   134,   130,   132,   136,   135,   131,     0,     0,\n      31\n};\n\nstatic const yytype_int16 yycheck[] =\n{\n      88,    50,   148,   151,   146,   153,    55,   154,   154,   145,\n      27,    60,   177,    31,    32,    64,    65,    66,    10,    33,\n      69,     0,   144,    72,    73,    74,    75,    34,   150,    10,\n      22,    80,    81,    82,    29,    84,    85,    86,    87,   147,\n      12,    22,   164,   151,   180,   153,   211,    31,    32,    31,\n      32,    28,    24,   195,   200,    31,    32,   193,   206,    30,\n      30,   149,    31,    32,    31,    32,    31,    32,   216,   191,\n      30,   218,   218,    31,    32,    31,    32,    31,    32,    31,\n      32,    30,   204,    30,    29,    31,    30,    30,    30,    30,\n     198,    30,    30,    30,    30,    30,    30,    30,   206,    29,\n     149,    29,    29,    76,    30,    29,   195,   214,   216,   214,\n     211,    79,   210,    77,   202,     3,     4,     5,     6,     7,\n       8,     9,    10,    11,    12,    13,    14,    15,    16,    17,\n      18,    19,    20,    21,    22,    23,    24,    25,    26,    87,\n      28,    -1,    -1,    83,    -1,    -1,    78,    35,     3,     4,\n       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,\n      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,\n      25,    26,    84,    80,    82,    86,    85,    81,    -1,    -1,\n      35\n};\n\n/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing\n   symbol of state STATE-NUM.  */\nstatic const yytype_uint8 yystos[] =\n{\n       0,    27,    37,    39,    41,    33,     0,     3,     4,     5,\n       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,\n      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,\n      26,    35,    40,    42,    43,    51,    59,    71,    86,    92,\n      98,   104,   114,   120,   126,   132,    34,    29,    45,    46,\n      47,    48,    49,    61,    62,    63,    64,    65,   106,   107,\n     108,   109,   110,    52,    93,   121,   133,    75,    77,    78,\n      79,    80,    87,   115,    99,   127,    44,    60,   105,    53,\n      94,   122,   134,    72,    88,   116,   100,   128,    38,    28,\n     142,    30,    50,   142,    68,    69,   142,   111,   112,    54,\n      55,   142,    95,    96,   142,   123,   124,   142,   135,   136,\n     142,   142,    83,    84,    89,    90,   142,   117,   118,   142,\n     101,   102,   142,   129,   130,   142,    45,    61,   106,    54,\n      95,   123,   135,    75,    89,   117,   101,   129,    40,    29,\n     138,   139,   140,   141,    30,    30,    30,    30,    30,    30,\n      30,    30,    30,    30,    30,    29,    31,    70,   138,    68,\n     113,    48,    56,    57,    58,    64,    97,   109,   125,    40,\n     137,   142,    85,   138,    64,    71,    91,    10,    22,    66,\n      67,    73,   119,    64,    71,   103,   109,   114,   131,    29,\n      31,    32,    31,    32,    31,    32,   138,    31,    32,    31,\n      32,    31,    32,    31,    32,    31,    32,    76,    77,    81,\n      82,    74,    68,    31,    32,    31,    32,    31,    32,    29,\n     138,    68,    57,    64,   109,    40,   138,    64,    71,    83,\n      76,    66,    73,    64,    71,   109,   114\n};\n\n#define yyerrok\t\t(yyerrstatus = 0)\n#define yyclearin\t(yychar = YYEMPTY)\n#define YYEMPTY\t\t(-2)\n#define YYEOF\t\t0\n\n#define YYACCEPT\tgoto yyacceptlab\n#define YYABORT\t\tgoto yyabortlab\n#define YYERROR\t\tgoto yyerrorlab\n\n\n/* Like YYERROR except do call yyerror.  This remains here temporarily\n   to ease the transition to the new meaning of YYERROR, for GCC.\n   Once GCC version 2 has supplanted version 1, this can go.  */\n\n#define YYFAIL\t\tgoto yyerrlab\n\n#define YYRECOVERING()  (!!yyerrstatus)\n\n#define YYBACKUP(Token, Value)\t\t\t\t\t\\\ndo\t\t\t\t\t\t\t\t\\\n  if (yychar == YYEMPTY && yylen == 1)\t\t\t\t\\\n    {\t\t\t\t\t\t\t\t\\\n      yychar = (Token);\t\t\t\t\t\t\\\n      yylval = (Value);\t\t\t\t\t\t\\\n      yytoken = YYTRANSLATE (yychar);\t\t\t\t\\\n      YYPOPSTACK (1);\t\t\t\t\t\t\\\n      goto yybackup;\t\t\t\t\t\t\\\n    }\t\t\t\t\t\t\t\t\\\n  else\t\t\t\t\t\t\t\t\\\n    {\t\t\t\t\t\t\t\t\\\n      yyerror (YY_(\"syntax error: cannot back up\")); \\\n      YYERROR;\t\t\t\t\t\t\t\\\n    }\t\t\t\t\t\t\t\t\\\nwhile (YYID (0))\n\n\n#define YYTERROR\t1\n#define YYERRCODE\t256\n\n\n/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].\n   If N is 0, then set CURRENT to the empty location which ends\n   the previous symbol: RHS[0] (always defined).  */\n\n#define YYRHSLOC(Rhs, K) ((Rhs)[K])\n#ifndef YYLLOC_DEFAULT\n# define YYLLOC_DEFAULT(Current, Rhs, N)\t\t\t\t\\\n    do\t\t\t\t\t\t\t\t\t\\\n      if (YYID (N))                                                    \\\n\t{\t\t\t\t\t\t\t\t\\\n\t  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;\t\\\n\t  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;\t\\\n\t  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;\t\t\\\n\t  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;\t\\\n\t}\t\t\t\t\t\t\t\t\\\n      else\t\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\\\n\t  (Current).first_line   = (Current).last_line   =\t\t\\\n\t    YYRHSLOC (Rhs, 0).last_line;\t\t\t\t\\\n\t  (Current).first_column = (Current).last_column =\t\t\\\n\t    YYRHSLOC (Rhs, 0).last_column;\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n    while (YYID (0))\n#endif\n\n\n/* YY_LOCATION_PRINT -- Print the location on the stream.\n   This macro was not mandated originally: define only if we know\n   we won't break user code: when these are the locations we know.  */\n\n#ifndef YY_LOCATION_PRINT\n# if YYLTYPE_IS_TRIVIAL\n#  define YY_LOCATION_PRINT(File, Loc)\t\t\t\\\n     fprintf (File, \"%d.%d-%d.%d\",\t\t\t\\\n\t      (Loc).first_line, (Loc).first_column,\t\\\n\t      (Loc).last_line,  (Loc).last_column)\n# else\n#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)\n# endif\n#endif\n\n\n/* YYLEX -- calling `yylex' with the right arguments.  */\n\n#ifdef YYLEX_PARAM\n# define YYLEX yylex (YYLEX_PARAM)\n#else\n# define YYLEX yylex ()\n#endif\n\n/* Enable debugging if requested.  */\n#if YYDEBUG\n\n# ifndef YYFPRINTF\n#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */\n#  define YYFPRINTF fprintf\n# endif\n\n# define YYDPRINTF(Args)\t\t\t\\\ndo {\t\t\t\t\t\t\\\n  if (yydebug)\t\t\t\t\t\\\n    YYFPRINTF Args;\t\t\t\t\\\n} while (YYID (0))\n\n# define YY_SYMBOL_PRINT(Title, Type, Value, Location)\t\t\t  \\\ndo {\t\t\t\t\t\t\t\t\t  \\\n  if (yydebug)\t\t\t\t\t\t\t\t  \\\n    {\t\t\t\t\t\t\t\t\t  \\\n      YYFPRINTF (stderr, \"%s \", Title);\t\t\t\t\t  \\\n      yy_symbol_print (stderr,\t\t\t\t\t\t  \\\n\t\t  Type, Value, Location); \\\n      YYFPRINTF (stderr, \"\\n\");\t\t\t\t\t\t  \\\n    }\t\t\t\t\t\t\t\t\t  \\\n} while (YYID (0))\n\n\n/*--------------------------------.\n| Print this symbol on YYOUTPUT.  |\n`--------------------------------*/\n\n/*ARGSUSED*/\n#if (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nstatic void\nyy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp)\n#else\nstatic void\nyy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp)\n    FILE *yyoutput;\n    int yytype;\n    YYSTYPE const * const yyvaluep;\n    YYLTYPE const * const yylocationp;\n#endif\n{\n  if (!yyvaluep)\n    return;\n  YYUSE (yylocationp);\n# ifdef YYPRINT\n  if (yytype < YYNTOKENS)\n    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);\n# else\n  YYUSE (yyoutput);\n# endif\n  switch (yytype)\n    {\n      default:\n\tbreak;\n    }\n}\n\n\n/*--------------------------------.\n| Print this symbol on YYOUTPUT.  |\n`--------------------------------*/\n\n#if (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nstatic void\nyy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp)\n#else\nstatic void\nyy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp)\n    FILE *yyoutput;\n    int yytype;\n    YYSTYPE const * const yyvaluep;\n    YYLTYPE const * const yylocationp;\n#endif\n{\n  if (yytype < YYNTOKENS)\n    YYFPRINTF (yyoutput, \"token %s (\", yytname[yytype]);\n  else\n    YYFPRINTF (yyoutput, \"nterm %s (\", yytname[yytype]);\n\n  YY_LOCATION_PRINT (yyoutput, *yylocationp);\n  YYFPRINTF (yyoutput, \": \");\n  yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp);\n  YYFPRINTF (yyoutput, \")\");\n}\n\n/*------------------------------------------------------------------.\n| yy_stack_print -- Print the state stack from its BOTTOM up to its |\n| TOP (included).                                                   |\n`------------------------------------------------------------------*/\n\n#if (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nstatic void\nyy_stack_print (yytype_int16 *bottom, yytype_int16 *top)\n#else\nstatic void\nyy_stack_print (bottom, top)\n    yytype_int16 *bottom;\n    yytype_int16 *top;\n#endif\n{\n  YYFPRINTF (stderr, \"Stack now\");\n  for (; bottom <= top; ++bottom)\n    YYFPRINTF (stderr, \" %d\", *bottom);\n  YYFPRINTF (stderr, \"\\n\");\n}\n\n# define YY_STACK_PRINT(Bottom, Top)\t\t\t\t\\\ndo {\t\t\t\t\t\t\t\t\\\n  if (yydebug)\t\t\t\t\t\t\t\\\n    yy_stack_print ((Bottom), (Top));\t\t\t\t\\\n} while (YYID (0))\n\n\n/*------------------------------------------------.\n| Report that the YYRULE is going to be reduced.  |\n`------------------------------------------------*/\n\n#if (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nstatic void\nyy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule)\n#else\nstatic void\nyy_reduce_print (yyvsp, yylsp, yyrule)\n    YYSTYPE *yyvsp;\n    YYLTYPE *yylsp;\n    int yyrule;\n#endif\n{\n  int yynrhs = yyr2[yyrule];\n  int yyi;\n  unsigned long int yylno = yyrline[yyrule];\n  YYFPRINTF (stderr, \"Reducing stack by rule %d (line %lu):\\n\",\n\t     yyrule - 1, yylno);\n  /* The symbols being reduced.  */\n  for (yyi = 0; yyi < yynrhs; yyi++)\n    {\n      fprintf (stderr, \"   $%d = \", yyi + 1);\n      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],\n\t\t       &(yyvsp[(yyi + 1) - (yynrhs)])\n\t\t       , &(yylsp[(yyi + 1) - (yynrhs)])\t\t       );\n      fprintf (stderr, \"\\n\");\n    }\n}\n\n# define YY_REDUCE_PRINT(Rule)\t\t\\\ndo {\t\t\t\t\t\\\n  if (yydebug)\t\t\t\t\\\n    yy_reduce_print (yyvsp, yylsp, Rule); \\\n} while (YYID (0))\n\n/* Nonzero means print parse trace.  It is left uninitialized so that\n   multiple parsers can coexist.  */\nint yydebug;\n#else /* !YYDEBUG */\n# define YYDPRINTF(Args)\n# define YY_SYMBOL_PRINT(Title, Type, Value, Location)\n# define YY_STACK_PRINT(Bottom, Top)\n# define YY_REDUCE_PRINT(Rule)\n#endif /* !YYDEBUG */\n\n\n/* YYINITDEPTH -- initial size of the parser's stacks.  */\n#ifndef\tYYINITDEPTH\n# define YYINITDEPTH 200\n#endif\n\n/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only\n   if the built-in stack extension method is used).\n\n   Do not make this value too large; the results are undefined if\n   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)\n   evaluated with infinite-precision integer arithmetic.  */\n\n#ifndef YYMAXDEPTH\n# define YYMAXDEPTH 10000\n#endif\n\n\f\n\n#if YYERROR_VERBOSE\n\n# ifndef yystrlen\n#  if defined __GLIBC__ && defined _STRING_H\n#   define yystrlen strlen\n#  else\n/* Return the length of YYSTR.  */\n#if (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nstatic YYSIZE_T\nyystrlen (const char *yystr)\n#else\nstatic YYSIZE_T\nyystrlen (yystr)\n    const char *yystr;\n#endif\n{\n  YYSIZE_T yylen;\n  for (yylen = 0; yystr[yylen]; yylen++)\n    continue;\n  return yylen;\n}\n#  endif\n# endif\n\n# ifndef yystpcpy\n#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE\n#   define yystpcpy stpcpy\n#  else\n/* Copy YYSRC to YYDEST, returning the address of the terminating '\\0' in\n   YYDEST.  */\n#if (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nstatic char *\nyystpcpy (char *yydest, const char *yysrc)\n#else\nstatic char *\nyystpcpy (yydest, yysrc)\n    char *yydest;\n    const char *yysrc;\n#endif\n{\n  char *yyd = yydest;\n  const char *yys = yysrc;\n\n  while ((*yyd++ = *yys++) != '\\0')\n    continue;\n\n  return yyd - 1;\n}\n#  endif\n# endif\n\n# ifndef yytnamerr\n/* Copy to YYRES the contents of YYSTR after stripping away unnecessary\n   quotes and backslashes, so that it's suitable for yyerror.  The\n   heuristic is that double-quoting is unnecessary unless the string\n   contains an apostrophe, a comma, or backslash (other than\n   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is\n   null, do not copy; instead, return the length of what the result\n   would have been.  */\nstatic YYSIZE_T\nyytnamerr (char *yyres, const char *yystr)\n{\n  if (*yystr == '\"')\n    {\n      YYSIZE_T yyn = 0;\n      char const *yyp = yystr;\n\n      for (;;)\n\tswitch (*++yyp)\n\t  {\n\t  case '\\'':\n\t  case ',':\n\t    goto do_not_strip_quotes;\n\n\t  case '\\\\':\n\t    if (*++yyp != '\\\\')\n\t      goto do_not_strip_quotes;\n\t    /* Fall through.  */\n\t  default:\n\t    if (yyres)\n\t      yyres[yyn] = *yyp;\n\t    yyn++;\n\t    break;\n\n\t  case '\"':\n\t    if (yyres)\n\t      yyres[yyn] = '\\0';\n\t    return yyn;\n\t  }\n    do_not_strip_quotes: ;\n    }\n\n  if (! yyres)\n    return yystrlen (yystr);\n\n  return yystpcpy (yyres, yystr) - yyres;\n}\n# endif\n\n/* Copy into YYRESULT an error message about the unexpected token\n   YYCHAR while in state YYSTATE.  Return the number of bytes copied,\n   including the terminating null byte.  If YYRESULT is null, do not\n   copy anything; just return the number of bytes that would be\n   copied.  As a special case, return 0 if an ordinary \"syntax error\"\n   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during\n   size calculation.  */\nstatic YYSIZE_T\nyysyntax_error (char *yyresult, int yystate, int yychar)\n{\n  int yyn = yypact[yystate];\n\n  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))\n    return 0;\n  else\n    {\n      int yytype = YYTRANSLATE (yychar);\n      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);\n      YYSIZE_T yysize = yysize0;\n      YYSIZE_T yysize1;\n      int yysize_overflow = 0;\n      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };\n      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];\n      int yyx;\n\n# if 0\n      /* This is so xgettext sees the translatable formats that are\n\t constructed on the fly.  */\n      YY_(\"syntax error, unexpected %s\");\n      YY_(\"syntax error, unexpected %s, expecting %s\");\n      YY_(\"syntax error, unexpected %s, expecting %s or %s\");\n      YY_(\"syntax error, unexpected %s, expecting %s or %s or %s\");\n      YY_(\"syntax error, unexpected %s, expecting %s or %s or %s or %s\");\n# endif\n      char *yyfmt;\n      char const *yyf;\n      static char const yyunexpected[] = \"syntax error, unexpected %s\";\n      static char const yyexpecting[] = \", expecting %s\";\n      static char const yyor[] = \" or %s\";\n      char yyformat[sizeof yyunexpected\n\t\t    + sizeof yyexpecting - 1\n\t\t    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)\n\t\t       * (sizeof yyor - 1))];\n      char const *yyprefix = yyexpecting;\n\n      /* Start YYX at -YYN if negative to avoid negative indexes in\n\t YYCHECK.  */\n      int yyxbegin = yyn < 0 ? -yyn : 0;\n\n      /* Stay within bounds of both yycheck and yytname.  */\n      int yychecklim = YYLAST - yyn + 1;\n      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;\n      int yycount = 1;\n\n      yyarg[0] = yytname[yytype];\n      yyfmt = yystpcpy (yyformat, yyunexpected);\n\n      for (yyx = yyxbegin; yyx < yyxend; ++yyx)\n\tif (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)\n\t  {\n\t    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)\n\t      {\n\t\tyycount = 1;\n\t\tyysize = yysize0;\n\t\tyyformat[sizeof yyunexpected - 1] = '\\0';\n\t\tbreak;\n\t      }\n\t    yyarg[yycount++] = yytname[yyx];\n\t    yysize1 = yysize + yytnamerr (0, yytname[yyx]);\n\t    yysize_overflow |= (yysize1 < yysize);\n\t    yysize = yysize1;\n\t    yyfmt = yystpcpy (yyfmt, yyprefix);\n\t    yyprefix = yyor;\n\t  }\n\n      yyf = YY_(yyformat);\n      yysize1 = yysize + yystrlen (yyf);\n      yysize_overflow |= (yysize1 < yysize);\n      yysize = yysize1;\n\n      if (yysize_overflow)\n\treturn YYSIZE_MAXIMUM;\n\n      if (yyresult)\n\t{\n\t  /* Avoid sprintf, as that infringes on the user's name space.\n\t     Don't have undefined behavior even if the translation\n\t     produced a string with the wrong number of \"%s\"s.  */\n\t  char *yyp = yyresult;\n\t  int yyi = 0;\n\t  while ((*yyp = *yyf) != '\\0')\n\t    {\n\t      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)\n\t\t{\n\t\t  yyp += yytnamerr (yyp, yyarg[yyi++]);\n\t\t  yyf += 2;\n\t\t}\n\t      else\n\t\t{\n\t\t  yyp++;\n\t\t  yyf++;\n\t\t}\n\t    }\n\t}\n      return yysize;\n    }\n}\n#endif /* YYERROR_VERBOSE */\n\f\n\n/*-----------------------------------------------.\n| Release the memory associated to this symbol.  |\n`-----------------------------------------------*/\n\n/*ARGSUSED*/\n#if (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nstatic void\nyydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp)\n#else\nstatic void\nyydestruct (yymsg, yytype, yyvaluep, yylocationp)\n    const char *yymsg;\n    int yytype;\n    YYSTYPE *yyvaluep;\n    YYLTYPE *yylocationp;\n#endif\n{\n  YYUSE (yyvaluep);\n  YYUSE (yylocationp);\n\n  if (!yymsg)\n    yymsg = \"Deleting\";\n  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);\n\n  switch (yytype)\n    {\n\n      default:\n\tbreak;\n    }\n}\n\f\n\n/* Prevent warnings from -Wmissing-prototypes.  */\n\n#ifdef YYPARSE_PARAM\n#if defined __STDC__ || defined __cplusplus\nint yyparse (void *YYPARSE_PARAM);\n#else\nint yyparse ();\n#endif\n#else /* ! YYPARSE_PARAM */\n#if defined __STDC__ || defined __cplusplus\nint yyparse (void);\n#else\nint yyparse ();\n#endif\n#endif /* ! YYPARSE_PARAM */\n\n\n\n/* The look-ahead symbol.  */\nint yychar;\n\n/* The semantic value of the look-ahead symbol.  */\nYYSTYPE yylval;\n\n/* Number of syntax errors so far.  */\nint yynerrs;\n/* Location data for the look-ahead symbol.  */\nYYLTYPE yylloc;\n\n\n\n/*----------.\n| yyparse.  |\n`----------*/\n\n#ifdef YYPARSE_PARAM\n#if (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nint\nyyparse (void *YYPARSE_PARAM)\n#else\nint\nyyparse (YYPARSE_PARAM)\n    void *YYPARSE_PARAM;\n#endif\n#else /* ! YYPARSE_PARAM */\n#if (defined __STDC__ || defined __C99__FUNC__ \\\n     || defined __cplusplus || defined _MSC_VER)\nint\nyyparse (void)\n#else\nint\nyyparse ()\n\n#endif\n#endif\n{\n  \n  int yystate;\n  int yyn;\n  int yyresult;\n  /* Number of tokens to shift before error messages enabled.  */\n  int yyerrstatus;\n  /* Look-ahead token as an internal (translated) token number.  */\n  int yytoken = 0;\n#if YYERROR_VERBOSE\n  /* Buffer for error messages, and its allocated size.  */\n  char yymsgbuf[128];\n  char *yymsg = yymsgbuf;\n  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;\n#endif\n\n  /* Three stacks and their tools:\n     `yyss': related to states,\n     `yyvs': related to semantic values,\n     `yyls': related to locations.\n\n     Refer to the stacks thru separate pointers, to allow yyoverflow\n     to reallocate them elsewhere.  */\n\n  /* The state stack.  */\n  yytype_int16 yyssa[YYINITDEPTH];\n  yytype_int16 *yyss = yyssa;\n  yytype_int16 *yyssp;\n\n  /* The semantic value stack.  */\n  YYSTYPE yyvsa[YYINITDEPTH];\n  YYSTYPE *yyvs = yyvsa;\n  YYSTYPE *yyvsp;\n\n  /* The location stack.  */\n  YYLTYPE yylsa[YYINITDEPTH];\n  YYLTYPE *yyls = yylsa;\n  YYLTYPE *yylsp;\n  /* The locations where the error started and ended.  */\n  YYLTYPE yyerror_range[2];\n\n#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N), yylsp -= (N))\n\n  YYSIZE_T yystacksize = YYINITDEPTH;\n\n  /* The variables used to return semantic value and location from the\n     action routines.  */\n  YYSTYPE yyval;\n  YYLTYPE yyloc;\n\n  /* The number of symbols on the RHS of the reduced rule.\n     Keep to zero when no symbol should be popped.  */\n  int yylen = 0;\n\n  YYDPRINTF ((stderr, \"Starting parse\\n\"));\n\n  yystate = 0;\n  yyerrstatus = 0;\n  yynerrs = 0;\n  yychar = YYEMPTY;\t\t/* Cause a token to be read.  */\n\n  /* Initialize stack pointers.\n     Waste one element of value and location stack\n     so that they stay on the same level as the state stack.\n     The wasted elements are never initialized.  */\n\n  yyssp = yyss;\n  yyvsp = yyvs;\n  yylsp = yyls;\n#if YYLTYPE_IS_TRIVIAL\n  /* Initialize the default location before parsing starts.  */\n  yylloc.first_line   = yylloc.last_line   = 1;\n  yylloc.first_column = yylloc.last_column = 0;\n#endif\n\n  goto yysetstate;\n\n/*------------------------------------------------------------.\n| yynewstate -- Push a new state, which is found in yystate.  |\n`------------------------------------------------------------*/\n yynewstate:\n  /* In all cases, when you get here, the value and location stacks\n     have just been pushed.  So pushing a state here evens the stacks.  */\n  yyssp++;\n\n yysetstate:\n  *yyssp = yystate;\n\n  if (yyss + yystacksize - 1 <= yyssp)\n    {\n      /* Get the current used size of the three stacks, in elements.  */\n      YYSIZE_T yysize = yyssp - yyss + 1;\n\n#ifdef yyoverflow\n      {\n\t/* Give user a chance to reallocate the stack.  Use copies of\n\t   these so that the &'s don't force the real ones into\n\t   memory.  */\n\tYYSTYPE *yyvs1 = yyvs;\n\tyytype_int16 *yyss1 = yyss;\n\tYYLTYPE *yyls1 = yyls;\n\n\t/* Each stack pointer address is followed by the size of the\n\t   data in use in that stack, in bytes.  This used to be a\n\t   conditional around just the two extra args, but that might\n\t   be undefined if yyoverflow is a macro.  */\n\tyyoverflow (YY_(\"memory exhausted\"),\n\t\t    &yyss1, yysize * sizeof (*yyssp),\n\t\t    &yyvs1, yysize * sizeof (*yyvsp),\n\t\t    &yyls1, yysize * sizeof (*yylsp),\n\t\t    &yystacksize);\n\tyyls = yyls1;\n\tyyss = yyss1;\n\tyyvs = yyvs1;\n      }\n#else /* no yyoverflow */\n# ifndef YYSTACK_RELOCATE\n      goto yyexhaustedlab;\n# else\n      /* Extend the stack our own way.  */\n      if (YYMAXDEPTH <= yystacksize)\n\tgoto yyexhaustedlab;\n      yystacksize *= 2;\n      if (YYMAXDEPTH < yystacksize)\n\tyystacksize = YYMAXDEPTH;\n\n      {\n\tyytype_int16 *yyss1 = yyss;\n\tunion yyalloc *yyptr =\n\t  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));\n\tif (! yyptr)\n\t  goto yyexhaustedlab;\n\tYYSTACK_RELOCATE (yyss);\n\tYYSTACK_RELOCATE (yyvs);\n\tYYSTACK_RELOCATE (yyls);\n#  undef YYSTACK_RELOCATE\n\tif (yyss1 != yyssa)\n\t  YYSTACK_FREE (yyss1);\n      }\n# endif\n#endif /* no yyoverflow */\n\n      yyssp = yyss + yysize - 1;\n      yyvsp = yyvs + yysize - 1;\n      yylsp = yyls + yysize - 1;\n\n      YYDPRINTF ((stderr, \"Stack size increased to %lu\\n\",\n\t\t  (unsigned long int) yystacksize));\n\n      if (yyss + yystacksize - 1 <= yyssp)\n\tYYABORT;\n    }\n\n  YYDPRINTF ((stderr, \"Entering state %d\\n\", yystate));\n\n  goto yybackup;\n\n/*-----------.\n| yybackup.  |\n`-----------*/\nyybackup:\n\n  /* Do appropriate processing given the current state.  Read a\n     look-ahead token if we need one and don't already have one.  */\n\n  /* First try to decide what to do without reference to look-ahead token.  */\n  yyn = yypact[yystate];\n  if (yyn == YYPACT_NINF)\n    goto yydefault;\n\n  /* Not known => get a look-ahead token if don't already have one.  */\n\n  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */\n  if (yychar == YYEMPTY)\n    {\n      YYDPRINTF ((stderr, \"Reading a token: \"));\n      yychar = YYLEX;\n    }\n\n  if (yychar <= YYEOF)\n    {\n      yychar = yytoken = YYEOF;\n      YYDPRINTF ((stderr, \"Now at end of input.\\n\"));\n    }\n  else\n    {\n      yytoken = YYTRANSLATE (yychar);\n      YY_SYMBOL_PRINT (\"Next token is\", yytoken, &yylval, &yylloc);\n    }\n\n  /* If the proper action on seeing token YYTOKEN is to reduce or to\n     detect an error, take that action.  */\n  yyn += yytoken;\n  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)\n    goto yydefault;\n  yyn = yytable[yyn];\n  if (yyn <= 0)\n    {\n      if (yyn == 0 || yyn == YYTABLE_NINF)\n\tgoto yyerrlab;\n      yyn = -yyn;\n      goto yyreduce;\n    }\n\n  if (yyn == YYFINAL)\n    YYACCEPT;\n\n  /* Count tokens shifted since error; after three, turn off error\n     status.  */\n  if (yyerrstatus)\n    yyerrstatus--;\n\n  /* Shift the look-ahead token.  */\n  YY_SYMBOL_PRINT (\"Shifting\", yytoken, &yylval, &yylloc);\n\n  /* Discard the shifted token unless it is eof.  */\n  if (yychar != YYEOF)\n    yychar = YYEMPTY;\n\n  yystate = yyn;\n  *++yyvsp = yylval;\n  *++yylsp = yylloc;\n  goto yynewstate;\n\n\n/*-----------------------------------------------------------.\n| yydefault -- do the default action for the current state.  |\n`-----------------------------------------------------------*/\nyydefault:\n  yyn = yydefact[yystate];\n  if (yyn == 0)\n    goto yyerrlab;\n  goto yyreduce;\n\n\n/*-----------------------------.\n| yyreduce -- Do a reduction.  |\n`-----------------------------*/\nyyreduce:\n  /* yyn is the number of a rule to reduce with.  */\n  yylen = yyr2[yyn];\n\n  /* If YYLEN is nonzero, implement the default value of the action:\n     `$$ = $1'.\n\n     Otherwise, the following line sets YYVAL to garbage.\n     This behavior is undocumented and Bison\n     users should not rely upon it.  Assigning to YYVAL\n     unconditionally makes the parser a bit smaller, and it avoids a\n     GCC warning that YYVAL may be used uninitialized.  */\n  yyval = yyvsp[1-yylen];\n\n  /* Default location.  */\n  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);\n  YY_REDUCE_PRINT (yyn);\n  switch (yyn)\n    {\n        case 2:\n#line 38 \"wktparse.y\"\n    { alloc_lwgeom(srid); }\n    break;\n\n  case 4:\n#line 40 \"wktparse.y\"\n    { alloc_lwgeom(-1); }\n    break;\n\n  case 19:\n#line 70 \"wktparse.y\"\n    { set_srid((yyvsp[(3) - (3)].value)); }\n    break;\n\n  case 20:\n#line 73 \"wktparse.y\"\n    { alloc_wkb((yyvsp[(1) - (1)].wkb)); }\n    break;\n\n  case 22:\n#line 81 \"wktparse.y\"\n    { set_zm(0, 1); }\n    break;\n\n  case 26:\n#line 89 \"wktparse.y\"\n    { alloc_point(); }\n    break;\n\n  case 27:\n#line 89 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 28:\n#line 92 \"wktparse.y\"\n    { alloc_point(); }\n    break;\n\n  case 29:\n#line 92 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 31:\n#line 100 \"wktparse.y\"\n    { alloc_multipoint(); }\n    break;\n\n  case 32:\n#line 100 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 33:\n#line 102 \"wktparse.y\"\n    { set_zm(0, 1); alloc_multipoint(); }\n    break;\n\n  case 34:\n#line 102 \"wktparse.y\"\n    {pop(); }\n    break;\n\n  case 36:\n#line 107 \"wktparse.y\"\n    { alloc_counter(); }\n    break;\n\n  case 37:\n#line 107 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 41:\n#line 118 \"wktparse.y\"\n    { alloc_point(); }\n    break;\n\n  case 42:\n#line 118 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 44:\n#line 126 \"wktparse.y\"\n    { set_zm(0, 1); }\n    break;\n\n  case 48:\n#line 134 \"wktparse.y\"\n    { alloc_linestring(); }\n    break;\n\n  case 49:\n#line 134 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 50:\n#line 137 \"wktparse.y\"\n    { alloc_linestring(); }\n    break;\n\n  case 51:\n#line 137 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 52:\n#line 140 \"wktparse.y\"\n    { alloc_linestring_closed(); }\n    break;\n\n  case 53:\n#line 140 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 54:\n#line 143 \"wktparse.y\"\n    { alloc_counter(); }\n    break;\n\n  case 55:\n#line 143 \"wktparse.y\"\n    { popc(); }\n    break;\n\n  case 59:\n#line 155 \"wktparse.y\"\n    {set_zm(0, 1); }\n    break;\n\n  case 62:\n#line 160 \"wktparse.y\"\n    {set_zm(0, 1); }\n    break;\n\n  case 68:\n#line 173 \"wktparse.y\"\n    { alloc_circularstring(); }\n    break;\n\n  case 69:\n#line 173 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 70:\n#line 176 \"wktparse.y\"\n    { alloc_circularstring(); }\n    break;\n\n  case 71:\n#line 176 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 72:\n#line 179 \"wktparse.y\"\n    { alloc_circularstring_closed(); }\n    break;\n\n  case 73:\n#line 179 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 74:\n#line 182 \"wktparse.y\"\n    { alloc_counter(); }\n    break;\n\n  case 75:\n#line 182 \"wktparse.y\"\n    { popc(); }\n    break;\n\n  case 78:\n#line 192 \"wktparse.y\"\n    { alloc_compoundcurve(); }\n    break;\n\n  case 79:\n#line 192 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 80:\n#line 194 \"wktparse.y\"\n    {set_zm(0, 1); alloc_compoundcurve(); }\n    break;\n\n  case 81:\n#line 194 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 83:\n#line 199 \"wktparse.y\"\n    { alloc_counter(); }\n    break;\n\n  case 84:\n#line 199 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 89:\n#line 213 \"wktparse.y\"\n    { alloc_multilinestring(); }\n    break;\n\n  case 90:\n#line 214 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 91:\n#line 216 \"wktparse.y\"\n    { set_zm(0, 1); alloc_multilinestring(); }\n    break;\n\n  case 92:\n#line 217 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 94:\n#line 222 \"wktparse.y\"\n    { alloc_counter(); }\n    break;\n\n  case 95:\n#line 222 \"wktparse.y\"\n    { pop();}\n    break;\n\n  case 98:\n#line 232 \"wktparse.y\"\n    { alloc_multicurve(); }\n    break;\n\n  case 99:\n#line 233 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 100:\n#line 235 \"wktparse.y\"\n    { set_zm(0, 1); alloc_multicurve(); }\n    break;\n\n  case 101:\n#line 236 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 103:\n#line 241 \"wktparse.y\"\n    { alloc_counter(); }\n    break;\n\n  case 104:\n#line 241 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 110:\n#line 257 \"wktparse.y\"\n    { set_zm(0, 1); }\n    break;\n\n  case 114:\n#line 265 \"wktparse.y\"\n    { alloc_polygon(); }\n    break;\n\n  case 115:\n#line 265 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 116:\n#line 268 \"wktparse.y\"\n    { alloc_polygon(); }\n    break;\n\n  case 117:\n#line 268 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 118:\n#line 271 \"wktparse.y\"\n    { alloc_counter(); }\n    break;\n\n  case 119:\n#line 271 \"wktparse.y\"\n    { pop();}\n    break;\n\n  case 122:\n#line 281 \"wktparse.y\"\n    { alloc_curvepolygon(); }\n    break;\n\n  case 123:\n#line 281 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 124:\n#line 283 \"wktparse.y\"\n    { set_zm(0, 1); alloc_curvepolygon(); }\n    break;\n\n  case 125:\n#line 284 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 127:\n#line 289 \"wktparse.y\"\n    { alloc_counter(); }\n    break;\n\n  case 128:\n#line 289 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 133:\n#line 303 \"wktparse.y\"\n    { alloc_multipolygon(); }\n    break;\n\n  case 134:\n#line 303 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 135:\n#line 305 \"wktparse.y\"\n    { set_zm(0, 1); alloc_multipolygon(); }\n    break;\n\n  case 136:\n#line 306 \"wktparse.y\"\n    { pop();}\n    break;\n\n  case 138:\n#line 311 \"wktparse.y\"\n    { alloc_counter(); }\n    break;\n\n  case 139:\n#line 311 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 142:\n#line 321 \"wktparse.y\"\n    {alloc_multisurface(); }\n    break;\n\n  case 143:\n#line 321 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 144:\n#line 323 \"wktparse.y\"\n    { set_zm(0, 1); alloc_multisurface(); }\n    break;\n\n  case 145:\n#line 324 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 147:\n#line 329 \"wktparse.y\"\n    { alloc_counter(); }\n    break;\n\n  case 148:\n#line 329 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 153:\n#line 343 \"wktparse.y\"\n    { alloc_geomertycollection(); }\n    break;\n\n  case 154:\n#line 344 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 155:\n#line 346 \"wktparse.y\"\n    { set_zm(0, 1); alloc_geomertycollection(); }\n    break;\n\n  case 156:\n#line 347 \"wktparse.y\"\n    { pop();}\n    break;\n\n  case 158:\n#line 352 \"wktparse.y\"\n    { alloc_counter(); }\n    break;\n\n  case 159:\n#line 352 \"wktparse.y\"\n    { pop(); }\n    break;\n\n  case 166:\n#line 371 \"wktparse.y\"\n    {alloc_point_2d((yyvsp[(1) - (2)].value),(yyvsp[(2) - (2)].value)); }\n    break;\n\n  case 167:\n#line 374 \"wktparse.y\"\n    {alloc_point_3d((yyvsp[(1) - (3)].value),(yyvsp[(2) - (3)].value),(yyvsp[(3) - (3)].value)); }\n    break;\n\n  case 168:\n#line 377 \"wktparse.y\"\n    {alloc_point_4d((yyvsp[(1) - (4)].value),(yyvsp[(2) - (4)].value),(yyvsp[(3) - (4)].value),(yyvsp[(4) - (4)].value)); }\n    break;\n\n  case 169:\n#line 380 \"wktparse.y\"\n    { alloc_empty(); }\n    break;\n\n\n/* Line 1267 of yacc.c.  */\n#line 2128 \"y.tab.c\"\n      default: break;\n    }\n  YY_SYMBOL_PRINT (\"-> $$ =\", yyr1[yyn], &yyval, &yyloc);\n\n  YYPOPSTACK (yylen);\n  yylen = 0;\n  YY_STACK_PRINT (yyss, yyssp);\n\n  *++yyvsp = yyval;\n  *++yylsp = yyloc;\n\n  /* Now `shift' the result of the reduction.  Determine what state\n     that goes to, based on the state we popped back to and the rule\n     number reduced by.  */\n\n  yyn = yyr1[yyn];\n\n  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;\n  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)\n    yystate = yytable[yystate];\n  else\n    yystate = yydefgoto[yyn - YYNTOKENS];\n\n  goto yynewstate;\n\n\n/*------------------------------------.\n| yyerrlab -- here on detecting error |\n`------------------------------------*/\nyyerrlab:\n  /* If not already recovering from an error, report this error.  */\n  if (!yyerrstatus)\n    {\n      ++yynerrs;\n#if ! YYERROR_VERBOSE\n      yyerror (YY_(\"syntax error\"));\n#else\n      {\n\tYYSIZE_T yysize = yysyntax_error (0, yystate, yychar);\n\tif (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)\n\t  {\n\t    YYSIZE_T yyalloc = 2 * yysize;\n\t    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))\n\t      yyalloc = YYSTACK_ALLOC_MAXIMUM;\n\t    if (yymsg != yymsgbuf)\n\t      YYSTACK_FREE (yymsg);\n\t    yymsg = (char *) YYSTACK_ALLOC (yyalloc);\n\t    if (yymsg)\n\t      yymsg_alloc = yyalloc;\n\t    else\n\t      {\n\t\tyymsg = yymsgbuf;\n\t\tyymsg_alloc = sizeof yymsgbuf;\n\t      }\n\t  }\n\n\tif (0 < yysize && yysize <= yymsg_alloc)\n\t  {\n\t    (void) yysyntax_error (yymsg, yystate, yychar);\n\t    yyerror (yymsg);\n\t  }\n\telse\n\t  {\n\t    yyerror (YY_(\"syntax error\"));\n\t    if (yysize != 0)\n\t      goto yyexhaustedlab;\n\t  }\n      }\n#endif\n    }\n\n  yyerror_range[0] = yylloc;\n\n  if (yyerrstatus == 3)\n    {\n      /* If just tried and failed to reuse look-ahead token after an\n\t error, discard it.  */\n\n      if (yychar <= YYEOF)\n\t{\n\t  /* Return failure if at end of input.  */\n\t  if (yychar == YYEOF)\n\t    YYABORT;\n\t}\n      else\n\t{\n\t  yydestruct (\"Error: discarding\",\n\t\t      yytoken, &yylval, &yylloc);\n\t  yychar = YYEMPTY;\n\t}\n    }\n\n  /* Else will try to reuse look-ahead token after shifting the error\n     token.  */\n  goto yyerrlab1;\n\n\n/*---------------------------------------------------.\n| yyerrorlab -- error raised explicitly by YYERROR.  |\n`---------------------------------------------------*/\nyyerrorlab:\n\n  /* Pacify compilers like GCC when the user code never invokes\n     YYERROR and the label yyerrorlab therefore never appears in user\n     code.  */\n  if (/*CONSTCOND*/ 0)\n     goto yyerrorlab;\n\n  yyerror_range[0] = yylsp[1-yylen];\n  /* Do not reclaim the symbols of the rule which action triggered\n     this YYERROR.  */\n  YYPOPSTACK (yylen);\n  yylen = 0;\n  YY_STACK_PRINT (yyss, yyssp);\n  yystate = *yyssp;\n  goto yyerrlab1;\n\n\n/*-------------------------------------------------------------.\n| yyerrlab1 -- common code for both syntax error and YYERROR.  |\n`-------------------------------------------------------------*/\nyyerrlab1:\n  yyerrstatus = 3;\t/* Each real token shifted decrements this.  */\n\n  for (;;)\n    {\n      yyn = yypact[yystate];\n      if (yyn != YYPACT_NINF)\n\t{\n\t  yyn += YYTERROR;\n\t  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)\n\t    {\n\t      yyn = yytable[yyn];\n\t      if (0 < yyn)\n\t\tbreak;\n\t    }\n\t}\n\n      /* Pop the current state because it cannot handle the error token.  */\n      if (yyssp == yyss)\n\tYYABORT;\n\n      yyerror_range[0] = *yylsp;\n      yydestruct (\"Error: popping\",\n\t\t  yystos[yystate], yyvsp, yylsp);\n      YYPOPSTACK (1);\n      yystate = *yyssp;\n      YY_STACK_PRINT (yyss, yyssp);\n    }\n\n  if (yyn == YYFINAL)\n    YYACCEPT;\n\n  *++yyvsp = yylval;\n\n  yyerror_range[1] = yylloc;\n  /* Using YYLLOC is tempting, but would change the location of\n     the look-ahead.  YYLOC is available though.  */\n  YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);\n  *++yylsp = yyloc;\n\n  /* Shift the error token.  */\n  YY_SYMBOL_PRINT (\"Shifting\", yystos[yyn], yyvsp, yylsp);\n\n  yystate = yyn;\n  goto yynewstate;\n\n\n/*-------------------------------------.\n| yyacceptlab -- YYACCEPT comes here.  |\n`-------------------------------------*/\nyyacceptlab:\n  yyresult = 0;\n  goto yyreturn;\n\n/*-----------------------------------.\n| yyabortlab -- YYABORT comes here.  |\n`-----------------------------------*/\nyyabortlab:\n  yyresult = 1;\n  goto yyreturn;\n\n#ifndef yyoverflow\n/*-------------------------------------------------.\n| yyexhaustedlab -- memory exhaustion comes here.  |\n`-------------------------------------------------*/\nyyexhaustedlab:\n  yyerror (YY_(\"memory exhausted\"));\n  yyresult = 2;\n  /* Fall through.  */\n#endif\n\nyyreturn:\n  if (yychar != YYEOF && yychar != YYEMPTY)\n     yydestruct (\"Cleanup: discarding lookahead\",\n\t\t yytoken, &yylval, &yylloc);\n  /* Do not reclaim the symbols of the rule which action triggered\n     this YYABORT or YYACCEPT.  */\n  YYPOPSTACK (yylen);\n  YY_STACK_PRINT (yyss, yyssp);\n  while (yyssp != yyss)\n    {\n      yydestruct (\"Cleanup: popping\",\n\t\t  yystos[*yyssp], yyvsp, yylsp);\n      YYPOPSTACK (1);\n    }\n#ifndef yyoverflow\n  if (yyss != yyssa)\n    YYSTACK_FREE (yyss);\n#endif\n#if YYERROR_VERBOSE\n  if (yymsg != yymsgbuf)\n    YYSTACK_FREE (yymsg);\n#endif\n  /* Make sure YYID is used.  */\n  return YYID (yyresult);\n}\n\n\n#line 381 \"wktparse.y\"\n\n\n\n\n\n\n"
  },
  {
    "path": "src/liblwgeom/wktparse.tab.h",
    "content": "/* A Bison parser, made by GNU Bison 2.3.  */\n\n/* Skeleton interface for Bison's Yacc-like parsers in C\n\n   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006\n   Free Software Foundation, Inc.\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2, or (at your option)\n   any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 51 Franklin Street, Fifth Floor,\n   Boston, MA 02110-1301, USA.  */\n\n/* As a special exception, you may create a larger work that contains\n   part or all of the Bison parser skeleton and distribute that work\n   under terms of your choice, so long as that work isn't itself a\n   parser generator using the skeleton or a modified version thereof\n   as a parser skeleton.  Alternatively, if you modify or redistribute\n   the parser skeleton itself, you may (at your option) remove this\n   special exception, which will cause the skeleton and the resulting\n   Bison output files to be licensed under the GNU General Public\n   License without this special exception.\n\n   This special exception was added by the Free Software Foundation in\n   version 2.2 of Bison.  */\n\n/* Tokens.  */\n#ifndef YYTOKENTYPE\n# define YYTOKENTYPE\n   /* Put the tokens into the symbol table, so that GDB and other debuggers\n      know about them.  */\n   enum yytokentype {\n     POINT = 258,\n     LINESTRING = 259,\n     POLYGON = 260,\n     MULTIPOINT = 261,\n     MULTILINESTRING = 262,\n     MULTIPOLYGON = 263,\n     GEOMETRYCOLLECTION = 264,\n     CIRCULARSTRING = 265,\n     COMPOUNDCURVE = 266,\n     CURVEPOLYGON = 267,\n     MULTICURVE = 268,\n     MULTISURFACE = 269,\n     POINTM = 270,\n     LINESTRINGM = 271,\n     POLYGONM = 272,\n     MULTIPOINTM = 273,\n     MULTILINESTRINGM = 274,\n     MULTIPOLYGONM = 275,\n     GEOMETRYCOLLECTIONM = 276,\n     CIRCULARSTRINGM = 277,\n     COMPOUNDCURVEM = 278,\n     CURVEPOLYGONM = 279,\n     MULTICURVEM = 280,\n     MULTISURFACEM = 281,\n     SRID = 282,\n     EMPTY = 283,\n     VALUE = 284,\n     LPAREN = 285,\n     RPAREN = 286,\n     COMMA = 287,\n     EQUALS = 288,\n     SEMICOLON = 289,\n     WKB = 290\n   };\n#endif\n/* Tokens.  */\n#define POINT 258\n#define LINESTRING 259\n#define POLYGON 260\n#define MULTIPOINT 261\n#define MULTILINESTRING 262\n#define MULTIPOLYGON 263\n#define GEOMETRYCOLLECTION 264\n#define CIRCULARSTRING 265\n#define COMPOUNDCURVE 266\n#define CURVEPOLYGON 267\n#define MULTICURVE 268\n#define MULTISURFACE 269\n#define POINTM 270\n#define LINESTRINGM 271\n#define POLYGONM 272\n#define MULTIPOINTM 273\n#define MULTILINESTRINGM 274\n#define MULTIPOLYGONM 275\n#define GEOMETRYCOLLECTIONM 276\n#define CIRCULARSTRINGM 277\n#define COMPOUNDCURVEM 278\n#define CURVEPOLYGONM 279\n#define MULTICURVEM 280\n#define MULTISURFACEM 281\n#define SRID 282\n#define EMPTY 283\n#define VALUE 284\n#define LPAREN 285\n#define RPAREN 286\n#define COMMA 287\n#define EQUALS 288\n#define SEMICOLON 289\n#define WKB 290\n\n\n\n\n#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED\ntypedef union YYSTYPE\n#line 22 \"wktparse.y\"\n{\n\tdouble value;\n\tconst char* wkb;\n}\n/* Line 1489 of yacc.c.  */\n#line 124 \"y.tab.h\"\n\tYYSTYPE;\n# define yystype YYSTYPE /* obsolescent; will be withdrawn */\n# define YYSTYPE_IS_DECLARED 1\n# define YYSTYPE_IS_TRIVIAL 1\n#endif\n\nextern YYSTYPE lwg_parse_yylval;\n\n#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED\ntypedef struct YYLTYPE\n{\n  int first_line;\n  int first_column;\n  int last_line;\n  int last_column;\n} YYLTYPE;\n# define yyltype YYLTYPE /* obsolescent; will be withdrawn */\n# define YYLTYPE_IS_DECLARED 1\n# define YYLTYPE_IS_TRIVIAL 1\n#endif\n\nextern YYLTYPE lwg_parse_yylloc;\n"
  },
  {
    "path": "src/liblwgeom/wktparse.y",
    "content": "/*\n * Written by Ralph Mason ralph.mason<at>telogis.com\n *\n * Copyright Telogis 2004\n * www.telogis.com\n *\n */\n\n%{\n#include \"wktparse.h\"\n#include <unistd.h>\n#include <stdio.h>\n\nvoid set_zm(char z, char m);\nint lwg_parse_yylex(void);\n%}\n\n%start geometry\n\n%locations\n\n%union {\n\tdouble value;\n\tconst char* wkb;\n}\n\n%token POINT LINESTRING POLYGON MULTIPOINT MULTILINESTRING MULTIPOLYGON GEOMETRYCOLLECTION CIRCULARSTRING COMPOUNDCURVE CURVEPOLYGON MULTICURVE MULTISURFACE\n%token POINTM LINESTRINGM POLYGONM MULTIPOINTM MULTILINESTRINGM MULTIPOLYGONM GEOMETRYCOLLECTIONM CIRCULARSTRINGM COMPOUNDCURVEM CURVEPOLYGONM  MULTICURVEM MULTISURFACEM\n%token SRID      \n%token EMPTY\n%token <value> VALUE\n%token LPAREN RPAREN COMMA EQUALS SEMICOLON\n%token  <wkb> WKB\n\n%%\n\ngeometry :\n\tsrid  SEMICOLON  { alloc_lwgeom(srid); } geometry_int \n\t|\n\t{ alloc_lwgeom(-1); } geometry_int\n\ngeometry_int :\n\tgeom_wkb\n\t|\n\tgeom_point\n\t|\n\tgeom_linestring\n\t|\n        geom_circularstring\n        |\n\tgeom_polygon\n\t|\n        geom_compoundcurve\n        |\n        geom_curvepolygon\n        |\n\tgeom_multipoint \n\t|\n\tgeom_multilinestring\n        |\n        geom_multicurve\n\t|\n\tgeom_multipolygon\n\t|\n        geom_multisurface\n        |\n\tgeom_geometrycollection\n\nsrid :\n\tSRID EQUALS VALUE { set_srid($3); } \n\ngeom_wkb :\n\tWKB { alloc_wkb($1); }\n\n\n/* POINT */\n\ngeom_point :\n\tPOINT point\n\t|\n\tPOINTM { set_zm(0, 1); } point \n\npoint :\n\tempty_point\n\t|\n\tnonempty_point\n\nempty_point :\n\t{ alloc_point(); } empty { pop(); } \n\nnonempty_point :\n\t{ alloc_point(); } point_int { pop(); } \n\npoint_int :\n\tLPAREN a_point RPAREN\n\n/* MULTIPOINT */\n\ngeom_multipoint :\n\tMULTIPOINT { alloc_multipoint(); } multipoint  { pop(); }\n\t| \n\tMULTIPOINTM { set_zm(0, 1); alloc_multipoint(); } multipoint {pop(); }\n\nmultipoint :\n\tempty\n\t|\n\t{ alloc_counter(); } LPAREN multipoint_int RPAREN { pop(); } \n\nmultipoint_int :\n\tmpoint_element\n\t|\n\tmultipoint_int COMMA mpoint_element\n\nmpoint_element :\n\tnonempty_point\n\t|\n\t/* this is to allow MULTIPOINT(0 0, 1 1) */\n\t{ alloc_point(); } a_point { pop(); }\n\n\n/* LINESTRING */\n\ngeom_linestring :\n\tLINESTRING linestring\n\t|\n\tLINESTRINGM { set_zm(0, 1); } linestring\n\nlinestring :\n\tempty_linestring\n\t|\n\tnonempty_linestring\n\nempty_linestring :\n\t{ alloc_linestring(); } empty { pop(); } \n\nnonempty_linestring :\n\t{ alloc_linestring(); } linestring_1 { pop(); } \n\nnonempty_linestring_closed :\n        { alloc_linestring_closed(); } linestring_1 { pop(); }\n\nlinestring_1 :\n\t{ alloc_counter(); } LPAREN linestring_int RPAREN { popc(); }\n\nlinestring_int :\n\ta_point\n\t|\n\tlinestring_int COMMA a_point;\n\n/* CIRCULARSTRING */\n\ngeom_circularstring :\n        CIRCULARSTRING circularstring\n        |\n        CIRCULARSTRINGM {set_zm(0, 1); } circularstring\n\ngeom_circularstring_closed :\n        CIRCULARSTRING circularstring_closed\n        |\n        CIRCULARSTRINGM {set_zm(0, 1); } circularstring_closed\n\ncircularstring :\n        empty_circularstring\n        |\n        nonempty_circularstring\n\ncircularstring_closed :\n        empty_circularstring\n        |\n        nonempty_circularstring_closed\n\nempty_circularstring :\n        { alloc_circularstring(); } empty { pop(); }\n\nnonempty_circularstring :\n        { alloc_circularstring(); } circularstring_1 { pop(); }\n\nnonempty_circularstring_closed :\n        { alloc_circularstring_closed(); } circularstring_1 { pop(); }\n\ncircularstring_1 :\n        { alloc_counter(); } LPAREN circularstring_int RPAREN { popc(); }\n\ncircularstring_int :\n        a_point\n        |\n        circularstring_int COMMA a_point;\n\n/* COMPOUNDCURVE */\n\ngeom_compoundcurve:\n        COMPOUNDCURVE { alloc_compoundcurve(); } compoundcurve { pop(); }\n        |\n        COMPOUNDCURVEM {set_zm(0, 1); alloc_compoundcurve(); } compoundcurve { pop(); }\n\ncompoundcurve:\n        empty\n        |\n        { alloc_counter(); } LPAREN compoundcurve_int RPAREN { pop(); }\n\ncompoundcurve_int:\n        nonempty_linestring\n        |\n        geom_circularstring\n        |\n        compoundcurve_int COMMA nonempty_linestring\n        |\n        compoundcurve_int COMMA geom_circularstring\n\n/* MULTILINESTRING */\n\ngeom_multilinestring :\n\tMULTILINESTRING { alloc_multilinestring(); }\n\t\tmultilinestring  { pop(); }\n\t|\n\tMULTILINESTRINGM { set_zm(0, 1); alloc_multilinestring(); }\n\t\tmultilinestring { pop(); } \n\nmultilinestring :\n\tempty\n\t|\n\t{ alloc_counter(); } LPAREN multilinestring_int RPAREN{ pop();}\n\nmultilinestring_int :\n\tnonempty_linestring\n\t|\n\tmultilinestring_int COMMA nonempty_linestring\n\n/* MULTICURVESTRING */\n\ngeom_multicurve :\n        MULTICURVE { alloc_multicurve(); }\n                multicurve { pop(); }\n        |\n        MULTICURVEM { set_zm(0, 1); alloc_multicurve(); }\n                multicurve { pop(); }\n\nmulticurve :\n        empty\n        |\n        { alloc_counter(); } LPAREN multicurve_int RPAREN { pop(); }\n\nmulticurve_int :\n        nonempty_linestring\n        |\n        geom_circularstring\n        |\n        multicurve_int COMMA nonempty_linestring\n        |\n        multicurve_int COMMA geom_circularstring\n\n/* POLYGON */\n\ngeom_polygon :\n\tPOLYGON polygon\n\t|\n\tPOLYGONM { set_zm(0, 1); } polygon \n\npolygon :\n\tempty_polygon\n\t|\n\tnonempty_polygon\n\nempty_polygon :\n\t{ alloc_polygon(); } empty  { pop(); } \n\nnonempty_polygon :\n\t{ alloc_polygon(); } polygon_1  { pop(); } \n\npolygon_1 :\n\t{ alloc_counter(); } LPAREN polygon_int RPAREN { pop();} \n\npolygon_int :\n\tlinestring_1\n\t|\n\tpolygon_int COMMA linestring_1\n\n/* CURVEPOLYGON */\n\ngeom_curvepolygon :\n        CURVEPOLYGON { alloc_curvepolygon(); } curvepolygon { pop(); }\n        |\n        CURVEPOLYGONM { set_zm(0, 1); alloc_curvepolygon(); } \n                        curvepolygon { pop(); }\n\ncurvepolygon :\n        empty\n        |\n        { alloc_counter(); } LPAREN curvepolygon_int RPAREN { pop(); }\n\ncurvepolygon_int :\n        nonempty_linestring_closed\n        |\n        geom_circularstring_closed\n        |\n        curvepolygon_int COMMA nonempty_linestring_closed\n        |\n        curvepolygon_int COMMA geom_circularstring_closed\n\n/* MULTIPOLYGON */\n\ngeom_multipolygon :\n\tMULTIPOLYGON { alloc_multipolygon(); } multipolygon { pop(); }\n\t|\n\tMULTIPOLYGONM { set_zm(0, 1); alloc_multipolygon(); }\n\t\tmultipolygon { pop();} \n\nmultipolygon :\n\tempty\n\t|\n\t{ alloc_counter(); } LPAREN multipolygon_int RPAREN { pop(); }\n\nmultipolygon_int :\n\tnonempty_polygon\n\t|\n\tmultipolygon_int COMMA nonempty_polygon\n\n/* MULTISURFACE */\n\ngeom_multisurface :\n        MULTISURFACE {alloc_multisurface(); } multisurface { pop(); }\n        |\n        MULTISURFACEM { set_zm(0, 1); alloc_multisurface(); }\n                multisurface { pop(); }\n\nmultisurface :\n        empty\n        |\n        { alloc_counter(); } LPAREN multisurface_int RPAREN { pop(); }\n\nmultisurface_int :\n        nonempty_polygon\n        |\n        geom_curvepolygon\n        |\n        multisurface_int COMMA nonempty_polygon\n        |\n        multisurface_int COMMA geom_curvepolygon\n\n/* GEOMETRYCOLLECTION */\n\ngeom_geometrycollection :\n\tGEOMETRYCOLLECTION { alloc_geomertycollection(); }\n\t\tgeometrycollection { pop(); }\n\t|\n\tGEOMETRYCOLLECTIONM { set_zm(0, 1); alloc_geomertycollection(); }\n\t\tgeometrycollection { pop();}\n\ngeometrycollection :\n\tempty\n\t|\n\t{ alloc_counter(); } LPAREN geometrycollection_int RPAREN { pop(); }\n\ngeometrycollection_int :\n\t/* to support GEOMETRYCOLLECTION(EMPTY) for backward compatibility */\n\tempty\n\t|\n\tgeometry_int\n\t|\n\tgeometrycollection_int COMMA geometry_int\n\n\na_point :\n\tpoint_2d\n\t|\n\tpoint_3d\n\t|\n\tpoint_4d \n\npoint_2d :\n\tVALUE VALUE {alloc_point_2d($1,$2); }\n\npoint_3d :\n\tVALUE VALUE VALUE {alloc_point_3d($1,$2,$3); }\n\npoint_4d :\n\tVALUE VALUE VALUE VALUE {alloc_point_4d($1,$2,$3,$4); }\n\nempty :\n\tEMPTY { alloc_empty(); }\n%%\n\n\n\n\n"
  },
  {
    "path": "src/libsqlite3_geocoder/Makefile",
    "content": "all: libsqlite3_geocoder.so\nCC=gcc -fPIC \n\n#extension.o:\n#\t$(CC) -lm -lsqlite3 -shared $^ -o $@\n\nlibsqlite3_geocoder.so: extension.o wkb_compress.o util.o metaphon.o levenshtein.o\n#\t$(CC) -lm -lsqlite3 -I/usr/include -shared $^ -o $@ \n\t$(CC) $^ -lm -lsqlite3 -shared -o $@ \n\ntest: test_wkb_compress test_levenshtein\n\n\ntest_wkb_compress: wkb_compress.c\n\t$(CC) -DTEST -o wkb_compress $^\n\ntest_levenshtein: levenshtein.c\n\t$(CC) -DTEST -o levenshtein $^\n\nclean:\n\trm -f *.o *.so wkb_compress levenshtein\n\ninstall:\n\tcp *.so ../../lib/geocoder/us/sqlite3.so\n\n"
  },
  {
    "path": "src/libsqlite3_geocoder/Makefile.nix",
    "content": "all: libsqlite3_geocoder.so\n\nlibsqlite3_geocoder.so: extension.o wkb_compress.o util.o metaphon.o levenshtein.o\n\t$(CC) -shared $^ -o $@\n\ntest: test_wkb_compress test_levenshtein\n\ntest_wkb_compress: wkb_compress.c\n\t$(CC) -DTEST -o wkb_compress $^\n\ntest_levenshtein: levenshtein.c\n\t$(CC) -DTEST -o levenshtein $^\n\nclean:\n\trm -f *.o *.so wkb_compress levenshtein\n"
  },
  {
    "path": "src/libsqlite3_geocoder/Makefile.redhat",
    "content": "all: libsqlite3_geocoder.so\nCFLAGS=-fPIC\nlibsqlite3_geocoder.so: extension.o wkb_compress.o util.o metaphon.o levenshtein.o\n\t$(CC) $(CFLAGS)  -shared $^ -o $@\n\t\ntest: test_wkb_compress test_levenshtein\n\ntest_wkb_compress: wkb_compress.c\n\t$(CC) -DTEST -o wkb_compress $^\n\ntest_levenshtein: levenshtein.c\n\t$(CC) -DTEST -o levenshtein $^\n\nclean:\n\trm -f *.o *.so wkb_compress levenshtein\n"
  },
  {
    "path": "src/libsqlite3_geocoder/extension.c",
    "content": "# include <sqlite3ext.h>\n# include <stdio.h>\n# include <string.h>\n# include <assert.h>\n# include <math.h>\n\n# include \"extension.h\"\n\nstatic SQLITE_EXTENSION_INIT1;\n\nstatic void\nsqlite3_metaphone (sqlite3_context *context, int argc, sqlite3_value **argv) {\n    const unsigned char *input = sqlite3_value_text(argv[0]);\n    int max_phones = 0;\n    char *output; \n    int len;\n    if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {\n        sqlite3_result_null(context);\n        return;\n    }\n    if (argc > 1)\n        max_phones = sqlite3_value_int(argv[1]);\n    if (max_phones <= 0)\n        max_phones = strlen(input);\n    output = sqlite3_malloc((max_phones+1)*sizeof(char));\n    len = metaphone(input, output, max_phones); \n    sqlite3_result_text(context, output, len, sqlite3_free);\n}\n\nstatic void\nsqlite3_levenshtein (sqlite3_context *context, int argc, sqlite3_value **argv) {\n    const unsigned char *s1 = sqlite3_value_text(argv[0]),\n                        *s2 = sqlite3_value_text(argv[1]);\n    double dist;\n    if (sqlite3_value_type(argv[0]) == SQLITE_NULL ||\n        sqlite3_value_type(argv[1]) == SQLITE_NULL) {\n        sqlite3_result_null(context);\n        return;\n    }\n    dist = levenshtein_distance(s1, s2);\n    sqlite3_result_double(context, dist);\n}\n\nstatic void\nsqlite3_digit_suffix (sqlite3_context *context,\n                           int argc, sqlite3_value **argv) {\n    if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {\n        sqlite3_result_null(context);\n        return;\n    }\n    const unsigned char *input = sqlite3_value_text(argv[0]);\n    char *output = sqlite3_malloc((strlen(input)+1) * sizeof(char));\n    size_t len = digit_suffix(input, output);\n    sqlite3_result_text(context, output, len, sqlite3_free);\n}\n\nstatic void\nsqlite3_nondigit_prefix (sqlite3_context *context,\n                           int argc, sqlite3_value **argv) {\n    if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {\n        sqlite3_result_null(context);\n        return;\n    }\n    const unsigned char *input = sqlite3_value_text(argv[0]);\n    char *output = sqlite3_malloc((strlen(input)+1) * sizeof(char));\n    size_t len = nondigit_prefix(input, output);\n    sqlite3_result_text(context, output, len, sqlite3_free);\n}\n\n\nstatic void\nsqlite3_compress_wkb_line (sqlite3_context *context,\n                           int argc, sqlite3_value **argv) {\n    if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {\n        sqlite3_result_null(context);\n        return;\n    }\n    unsigned long input_len = sqlite3_value_bytes(argv[0]);\n    const void *input = sqlite3_value_blob(argv[0]);\n    unsigned long output_len = ceil((input_len-9)/8.0) * 4;\n    unsigned long len = 0;\n    void *output = sqlite3_malloc(output_len);\n    len = compress_wkb_line(output, input, input_len); \n    assert(len == output_len);\n    sqlite3_result_blob(context, output, len, sqlite3_free);\n}\n\nstatic void\nsqlite3_uncompress_wkb_line (sqlite3_context *context,\n                           int argc, sqlite3_value **argv) {\n    unsigned long input_len = sqlite3_value_bytes(argv[0]);\n    const void *input = sqlite3_value_blob(argv[0]);\n    unsigned long output_len = input_len*2+9;\n    unsigned long len = 0;\n    void *output = sqlite3_malloc(output_len);\n    len = uncompress_wkb_line(output, input, input_len);\n    assert(len == output_len);\n    sqlite3_result_blob(context, output, len, sqlite3_free);\n}\n\nint sqlite3_extension_init (sqlite3 * db, char **pzErrMsg,\n                            const sqlite3_api_routines *pApi) {\n    SQLITE_EXTENSION_INIT2(pApi);\n    \n    sqlite3_create_function(db, \"metaphone\", 1, SQLITE_ANY,\n                            NULL, sqlite3_metaphone, NULL, NULL);\n    sqlite3_create_function(db, \"metaphone\", 2, SQLITE_ANY,\n                            NULL, sqlite3_metaphone, NULL, NULL);\n    \n    sqlite3_create_function(db, \"levenshtein\", 2, SQLITE_ANY,\n                            NULL, sqlite3_levenshtein, NULL, NULL);\n    sqlite3_create_function(db, \"compress_wkb_line\", 1, SQLITE_ANY,\n                            NULL, sqlite3_compress_wkb_line, NULL, NULL);\n    sqlite3_create_function(db, \"uncompress_wkb_line\", 1, SQLITE_ANY,\n                            NULL, sqlite3_uncompress_wkb_line, NULL, NULL);\n    sqlite3_create_function(db, \"digit_suffix\", 1, SQLITE_ANY,\n                            NULL, sqlite3_digit_suffix, NULL, NULL);\n    sqlite3_create_function(db, \"nondigit_prefix\", 1, SQLITE_ANY,\n                            NULL, sqlite3_nondigit_prefix, NULL, NULL);\n    return 0;\n}\n"
  },
  {
    "path": "src/libsqlite3_geocoder/extension.h",
    "content": "#ifndef SQLITE3_GEOCODER\n#define SQLITE3_GEOCODER\n\n#include <stdint.h>\n\nint metaphone(const char *Word, char *Metaph, int max_phones);\ndouble levenshtein_distance (const unsigned char *s1, const unsigned char *s2);\nsigned int rindex_nondigit (const char *string);\nsigned int nondigit_prefix (const char *input, char *output);\nuint32_t compress_wkb_line (void *dest, const void *src, uint32_t len);\nuint32_t uncompress_wkb_line (void *dest, const void *src, uint32_t len);\n\n#endif\n"
  },
  {
    "path": "src/libsqlite3_geocoder/levenshtein.c",
    "content": "# include <string.h>\n# define STRLEN_MAX 256\n# define min(x, y) ((x) < (y) ? (x) : (y))\n# define max(x, y) ((x) > (y) ? (x) : (y))\n# define NO_CASE (~(unsigned char)32)\n# define eql(x, y) (((x) & NO_CASE) == ((y) & NO_CASE))\n\nstatic int d[STRLEN_MAX][STRLEN_MAX]; // this isn't thread safe\n\ndouble levenshtein_distance (const unsigned char *s1, const unsigned char *s2) {\n    const size_t len1 = min(strlen(s1), STRLEN_MAX-1),\n                 len2 = min(strlen(s2), STRLEN_MAX-1);\n    int cost, i, j;\n\n    for (i = 1; i <= len1; ++i) d[i][0] = i;\n    for (i = 1; i <= len2; ++i) d[0][i] = i;\n    for (i = 1; i <= len1; ++i) {\n        for (j = 1; j <= len2; ++j) {\n            cost = (eql(s1[i-1], s2[j-1]) ? 0 : 1);\n            d[i][j] = min(min(\n                        d[i-1][j  ] + 1,              /* deletion */\n                        d[i  ][j-1] + 1),             /* insertion */\n                        d[i-1][j-1] + cost);          /* substitution */\n            if (i > 1 && j > 1 && eql(s1[i-1], s2[j-2]) && eql(s1[i-2], s2[j-1])) {\n               d[i][j] = min( d[i][j],\n                              d[i-2][j-2] + cost );   /* transposition */\n            }\n        }\n    }\n    return (d[len1][len2] / (double) max(len1, len2));\n}\n\n#ifdef TEST\n#include <stdio.h>\n\nint main (int argc, char **argv) {\n    if (argc < 3) return -1;\n    printf(\"%.1f%%\\n\", levenshtein_distance(argv[1],argv[2]) * 100);\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "src/libsqlite3_geocoder/metaphon.c",
    "content": "/* +++Customized by SDE for sqlite3 use 09-Mar-2009 */\n/* +++File obtained from http://www.shedai.net/c/new/METAPHON.C */\n/* +++Date previously modified: 05-Jul-1997 */\n\n/*\n**  METAPHON.C - Phonetic string matching\n**\n**  The Metaphone algorithm was developed by Lawrence Phillips. Like the\n**  Soundex algorithm, it compares words that sound alike but are spelled\n**  differently. Metaphone was designed to overcome difficulties encountered\n**  with Soundex.\n**\n**  This implementation was written by Gary A. Parker and originally published\n**  in the June/July, 1991 (vol. 5 nr. 4) issue of C Gazette. As published,\n**  this code was explicitly placed in the public domain by the author.\n*/\n\n#include <ctype.h>\n#include <string.h> /* strlen() */\n#include <stdio.h>\n#include <sqlite3.h>\n#define malloc(x) sqlite3_malloc((x))\n#define free(x) sqlite3_free((x))\n\n/*\n**  Character coding array\n*/\n\nstatic char vsvfn[26] = {\n      1,16,4,16,9,2,4,16,9,2,0,2,2,2,1,4,0,2,4,4,1,0,0,0,8,0};\n/*    A  B C  D E F G  H I J K L M N O P Q R S T U V W X Y Z      */\n\n/*\n**  Macros to access the character coding array\n*/\n\n#define vowel(x)  (vsvfn[(x) - 'A'] & 1)  /* AEIOU    */\n#define same(x)   (vsvfn[(x) - 'A'] & 2)  /* FJLMNR   */\n#define varson(x) (vsvfn[(x) - 'A'] & 4)  /* CGPST    */\n#define frontv(x) (vsvfn[(x) - 'A'] & 8)  /* EIY      */\n#define noghf(x)  (vsvfn[(x) - 'A'] & 16) /* BDH      */\n\nint metaphone(const char *Word, char *Metaph, int max_phones) {\n    char *n, *n_start, *n_end;    /* Pointers to string               */\n    char *metaph_start = Metaph, *metaph_end;    \n    /* Pointers to metaph         */\n    int ntrans_len = strlen(Word)+4;\n    char *ntrans = (char *)malloc(sizeof(char) * ntrans_len);\n    /* Word with uppercase letters      */\n    int KSflag;                   /* State flag for X translation     */\n\n    /* SDE -- special case: if the word starts with a number, just\n     * copy the leading digits and return. This means we don't\n     * metaphone cardinal number suffixes (i.e. \"st\",\"nd\",\"rd\") */\n    int leading_digit = isdigit(*Word);\n    /* SDE -- check for a leading semivowel. needed because\n     * the copy in ntrans gets destroyed by the metaphone process. */\n    char leading_semivowel = '\\0';\n\n    /*\n     ** Copy word to internal buffer, dropping non-alphabetic characters\n     ** and converting to upper case.\n     */\n    for (n = ntrans + 1, n_end = ntrans + ntrans_len - 2;\n            *Word && n < n_end; ++Word)\n    {\n        /* SDE -- see previous comment */\n        if (leading_digit && isalpha(*Word))\n            break;\n        /* SDE -- copy numbers as well, for geocoding street names */\n        /* was: if (isalpha(*Word)) */\n        if (isalnum(*Word)) \n            *n++ = toupper(*Word);\n    }\n\n    if (n == ntrans + 1) {\n        free(ntrans);\n        Metaph[0]='\\0';\n        return 0;           /* Return if zero characters        */\n    }\n    else  n_end = n;          /* Set end of string pointer        */\n\n    /*\n     ** Pad with '\\0's, front and rear\n     */\n\n    *n++ = '\\0';\n    *n   = '\\0';\n    n    = ntrans;\n    *n++ = '\\0';\n    \n    /* SDE: check for leading semivowel here */\n    if (ntrans[1] == 'W' || ntrans[1] == 'Y')\n        leading_semivowel = ntrans[1];\n\n    /*\n     ** Check for PN, KN, GN, WR, WH, and X at start\n     */\n\n    switch (*n)\n    {\n        case 'P':\n        case 'K':\n        case 'G':\n            if ('N' == *(n + 1))\n                *n++ = '\\0';\n            break;\n\n        case 'A':\n            if ('E' == *(n + 1))\n                *n++ = '\\0';\n            break;\n\n        case 'W':\n            if ('R' == *(n + 1))\n                *n++ = '\\0';\n            else if ('H' == *(n + 1))\n            {\n                *(n + 1) = *n;\n                *n++ = '\\0';\n            }\n            break;\n\n        case 'X':\n            *n = 'S';\n            break;\n    }\n\n    /*\n     ** Now loop through the string, stopping at the end of the string\n     ** or when the computed Metaphone code is max_phones characters long.\n     */\n\n    KSflag = 0;              /* State flag for KStranslation     */\n    for (metaph_end = Metaph + max_phones, n_start = n;\n            n <= n_end && Metaph < metaph_end; ++n)\n    {\n        if (KSflag)\n        {\n            KSflag = 0;\n            *Metaph++ = *n;\n        }\n        else\n        {\n            /* SDE -- special case: copy numbers verbatim */\n            if (isdigit(*n)) {\n                *Metaph++ = *n;\n                continue;\n            }\n\n            /* Drop duplicates except for CC    */\n            if (*(n - 1) == *n && *n != 'C')\n                continue;\n\n            /* Check for F J L M N R  or first letter vowel */\n\n            if (same(*n) || (n == n_start && vowel(*n)))\n                *Metaph++ = *n;\n            else switch (*n)\n            {\n                case 'B':\n                    if (n < n_end || *(n - 1) != 'M')\n                        *Metaph++ = *n;\n                    break;\n\n                case 'C':\n                    if (*(n - 1) != 'S' || !frontv(*(n + 1)))\n                    {\n                        if ('I' == *(n + 1) && 'A' == *(n + 2))\n                            *Metaph++ = 'X';\n                        else if (frontv(*(n + 1)))\n                            *Metaph++ = 'S';\n                        else if ('H' == *(n + 1))\n                            *Metaph++ = ((n == n_start &&\n                                        !vowel(*(n + 2))) ||\n                                    'S' == *(n - 1)) ? 'K' : 'X';\n                        else  *Metaph++ = 'K';\n                    }\n                    break;\n\n                case 'D':\n                    *Metaph++ = ('G' == *(n + 1) && frontv(*(n + 2))) ?\n                        'J' : 'T';\n                    break;\n\n                case 'G':\n                    if ((*(n + 1) != 'H' || vowel(*(n + 2))) &&\n                            (*(n + 1) != 'N' || ((n + 1) < n_end &&\n                                                 (*(n + 2) != 'E' || *(n + 3) != 'D'))) &&\n                            (*(n - 1) != 'D' || !frontv(*(n + 1))))\n                    {\n                        *Metaph++ = (frontv(*(n + 1)) &&\n                                *(n + 2) != 'G') ? 'J' : 'K';\n                    }\n                    else if ('H' == *(n + 1) && !noghf(*(n - 3)) &&\n                            *(n - 4) != 'H')\n                    {\n                        *Metaph++ = 'F';\n                    }\n                    break;\n\n                case 'H':\n                    if (!varson(*(n - 1)) && (!vowel(*(n - 1)) ||\n                                vowel(*(n + 1))))\n                    {\n                        *Metaph++ = 'H';\n                    }\n                    break;\n\n                case 'K':\n                    if (*(n - 1) != 'C')\n                        *Metaph++ = 'K';\n                    break;\n\n                case 'P':\n                    *Metaph++ = ('H' == *(n + 1)) ? 'F' : 'P';\n                    break;\n\n                case 'Q':\n                    *Metaph++ = 'K';\n                    break;\n\n                case 'S':\n                    *Metaph++ = ('H' == *(n + 1) || ('I' == *(n + 1) &&\n                                ('O' == *(n + 2) || 'A' == *(n + 2)))) ?\n                        'X' : 'S';\n                    break;\n\n                case 'T':\n                    if ('I' == *(n + 1) && ('O' == *(n + 2) ||\n                                'A' == *(n + 2)))\n                    {\n                        *Metaph++ = 'X';\n                    }\n                    else if ('H' == *(n + 1))\n                        /* SDE: was:\n                           *Metaph++ = 'O';\n                           but that's WRONG. */\n                        *Metaph++ = '0';\n                    else if (*(n + 1) != 'C' || *(n + 2) != 'H')\n                        *Metaph++ = 'T';\n                    break;\n\n                case 'V':\n                    *Metaph++ = 'F';\n                    break;\n\n                case 'W':\n                case 'Y':\n                    if (vowel(*(n + 1)))\n                        *Metaph++ = *n;\n                    break;\n\n                case 'X':\n                    if (n == n_start)\n                        *Metaph++ = 'S';\n                    else\n                    {\n                        *Metaph++ = 'K';\n                        KSflag = 1;\n                    }\n                    break;\n\n                case 'Z':\n                    *Metaph++ = 'S';\n                    break;\n            }\n        }\n    }\n\n    /* SDE: special case: if word consists solely of W or Y, use that. */\n    if (Metaph == metaph_start && leading_semivowel)\n        *Metaph++ = leading_semivowel;\n\n    *Metaph = '\\0';\n    free(ntrans);\n    return strlen(metaph_start);\n}\n\n"
  },
  {
    "path": "src/libsqlite3_geocoder/util.c",
    "content": "# include <string.h>\n# include <ctype.h>\n\nint address_metaphone(const char *input, char *output, int max_phones) {\n    const char *n = input;\n    int i = 0;\n    if (isdigit(*n)) {\n        while (i < max_phones && isdigit(n[i]) && n[i] != '\\0')\n            *output++ = n[i++];\n        *output = '\\0';\n        return 1;\n    } else {\n        return metaphone(input, output, max_phones);\n    }\n}\n\nsigned int rindex_nondigit (const char *string) {\n    signed int i = strlen(string);\n    if (!i) return -1;\n    for (i--; i >= 0 && isdigit(string[i]); i--);\n    return i;\n}\n\nsigned int digit_suffix (const char *input, char *output) {\n    signed int i = rindex_nondigit(input);\n    strcpy(output, input+i+1);\n    return strlen(output);\n}\n\nsigned int nondigit_prefix (const char *input, char *output) {\n    signed int i = rindex_nondigit(input);\n    if (i++ >= 0) {\n        strncpy(output, input, i);\n        output[i] = '\\0';\n    }\n    return i;\n}\n"
  },
  {
    "path": "src/libsqlite3_geocoder/wkb_compress.c",
    "content": "#include <stdint.h>\n#include <string.h>\n\nuint32_t compress_wkb_line (void *dest, const void *src, uint32_t len) {\n    uint32_t d, s;\n    double value;\n    if (!len) return 0;\n    for (s = 9, d = 0; s < len; d += 4, s += 8) {\n        value = *(double *)(src + s);\n        value *= 1000000;\n        *(int32_t *)(dest + d) = (int32_t) value;\n    }\n    return d; \n}\n\nuint32_t uncompress_wkb_line (void *dest, const void *src, uint32_t len) {\n    uint32_t d, s;\n    double value;\n    if (!len) return 0;\n    memcpy(dest, \"\\01\\02\\00\\00\\00\\06\\00\\00\\00\", 10);\n    for (s = 0, d = 9; s < len; s += 4, d += 8) {\n        value = (double) *(int32_t *)(src + s);\n        value /= 1000000;\n        *(double *)(dest + d) = value;\n    }\n    return d; \n}\n\n\n#ifdef TEST\n\n#include <stdio.h>\nint main (int argc, char *argv) {\n    char hex[1024], *scan;\n    char wkb[512];\n    unsigned long len, clen;\n    \n    while (!feof(stdin)) {\n        fgets(hex, sizeof(hex), stdin);\n        for (scan = hex, len = 0; *scan && sizeof(wkb)>len; scan += 2, len++) {\n            if (sscanf(scan, \"%2x\", (uint32_t *)(wkb+len)) != 1) break;\n        }\n        clen = compress_wkb_line(hex, wkb, len);\n        printf(\"before: %lu, after: %lu\\n\", len, clen);\n        len = uncompress_wkb_line(wkb, hex, clen);\n        printf(\"before: %lu, after: %lu\\n\", clen, len);\n        for (scan = wkb + 9; scan < wkb + len; scan += 8) {\n            printf(\"%.6f \", *(double *)scan);\n        }\n        printf(\"\\n\");\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/metaphone/Makefile",
    "content": "all: metaphone.so\n\nmetaphone.so: extension.o metaphon.o\n\t$(CC) -fPIC -shared $^ -o $@\n\nclean:\n\trm -f *.o *.so\n"
  },
  {
    "path": "src/metaphone/README",
    "content": "= SQLite 3 Metaphone extension =\n\n * This library implements the Metaphone algorithm, originally developed by\n   Laurence Phillips, as an SQLite 3 extension function:\n\n     http://en.wikipedia.org/wiki/Metaphone\n\n * This code is based around the original public domain implementation in\n   C by Gary Phillips, as provided by Sadi Evren Seker:\n\n    http://www.shedai.net/c/new/METAPHON.C\n\n * Like SQLite and the Phillips implementation of Metaphone, this code\n   is provided in the public domain, in the hope that it will be useful.\n\n * To compile the code, simply run `make`. You must have GNU Make and GCC\n   installed.\n\n * The module implements one function, metaphone(), which takes a string\n   to convert to a metaphone representation as its first argument, and an\n   optional second argument to specify the maximum length of the output.\n\n * To use the code, run `sqlite3` and enter the following:\n\n{{{\n    sqlite> .load /path/to/metaphone.so\n            -- you can use ./metaphone.so if the .so is in your \n            -- current directory, or just metaphone.so if it's\n            -- somewhere in your library path.\n    sqlite> select metaphone(\"Schuyler\");\n    SKLR\n    sqlite> select metaphone(\"Schuyler\", 3);\n    SKL\n    sqlite> select metaphone(\"Skyler\");\n    SKLR\n    sqlite> select metaphone(\"Skylar\");\n    SKLR\n    sqlite> select metaphone(\"SQLite rules!\");\n    SKLTRLS\n    sqlite> select metaphone(\"SQLite roolz!!!1!\");\n    SKLTRLS\n}}}\n\nQuestions? Comments? Complaints? Approbation? Email schuyler@nocat.net.\n\nSchuyler Erle\n9 March 2008\n\n=30=\n"
  },
  {
    "path": "src/metaphone/extension.c",
    "content": "# include <sqlite3.h>\n# include <sqlite3ext.h>\n# include <stdio.h>\n# include <string.h>\n\nstatic SQLITE_EXTENSION_INIT1;\n\nstatic void\nsqlite3_metaphone (sqlite3_context *context, int argc, sqlite3_value **argv) {\n    const unsigned char *input = sqlite3_value_text(argv[0]);\n    int max_phones = 0;\n    char *output; \n    int len;\n    if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {\n        sqlite3_result_null(context);\n        return;\n    }\n    if (argc > 1)\n        max_phones = sqlite3_value_int(argv[1]);\n    if (max_phones <= 0)\n        max_phones = strlen(input);\n    output = sqlite3_malloc((max_phones+1)*sizeof(char));\n    len = metaphone(input, output, max_phones); \n    sqlite3_result_text(context, output, len, SQLITE_TRANSIENT);\n}\n\nint sqlite3_extension_init (sqlite3 * db, char **pzErrMsg,\n                            const sqlite3_api_routines *pApi) {\n    SQLITE_EXTENSION_INIT2(pApi);\n    sqlite3_create_function(db, \"metaphone\", 1, SQLITE_ANY,\n                            NULL, sqlite3_metaphone, NULL, NULL);\n    sqlite3_create_function(db, \"metaphone\", 2, SQLITE_ANY,\n                            NULL, sqlite3_metaphone, NULL, NULL);\n    return 0;\n}\n\n\n"
  },
  {
    "path": "src/metaphone/metaphon.c",
    "content": "/* +++Customized by SDE for sqlite3 use 09-Mar-2009 */\n/* +++File obtained from http://www.shedai.net/c/new/METAPHON.C */\n/* +++Date previously modified: 05-Jul-1997 */\n\n/*\n**  METAPHON.C - Phonetic string matching\n**\n**  The Metaphone algorithm was developed by Lawrence Phillips. Like the\n**  Soundex algorithm, it compares words that sound alike but are spelled\n**  differently. Metaphone was designed to overcome difficulties encountered\n**  with Soundex.\n**\n**  This implementation was written by Gary A. Parker and originally published\n**  in the June/July, 1991 (vol. 5 nr. 4) issue of C Gazette. As published,\n**  this code was explicitly placed in the public domain by the author.\n*/\n\n#include <ctype.h>\n#include <string.h> /* strlen() */\n#include <stdio.h>\n#define malloc(x) sqlite3_malloc((x))\n#define free(x) sqlite3_free((x))\n\n/*\n**  Character coding array\n*/\n\nstatic char vsvfn[26] = {\n      1,16,4,16,9,2,4,16,9,2,0,2,2,2,1,4,0,2,4,4,1,0,0,0,8,0};\n/*    A  B C  D E F G  H I J K L M N O P Q R S T U V W X Y Z      */\n\n/*\n**  Macros to access the character coding array\n*/\n\n#define vowel(x)  (vsvfn[(x) - 'A'] & 1)  /* AEIOU    */\n#define same(x)   (vsvfn[(x) - 'A'] & 2)  /* FJLMNR   */\n#define varson(x) (vsvfn[(x) - 'A'] & 4)  /* CGPST    */\n#define frontv(x) (vsvfn[(x) - 'A'] & 8)  /* EIY      */\n#define noghf(x)  (vsvfn[(x) - 'A'] & 16) /* BDH      */\n\nint metaphone(const char *Word, char *Metaph, int max_phones)\n{\n      char *n, *n_start, *n_end;    /* Pointers to string               */\n      char *metaph_start = Metaph, *metaph_end;    \n                                    /* Pointers to metaph         */\n      int ntrans_len = strlen(Word)+4;\n      char *ntrans = (char *)malloc(sizeof(char) * ntrans_len);\n                                    /* Word with uppercase letters      */\n      int KSflag;                   /* State flag for X translation     */\n\n      /*\n      ** Copy word to internal buffer, dropping non-alphabetic characters\n      ** and converting to upper case.\n      */\n\n      for (n = ntrans + 1, n_end = ntrans + ntrans_len - 2;\n            *Word && n < n_end; ++Word)\n      {\n            if (isalpha(*Word))\n                  *n++ = toupper(*Word);\n      }\n\n      if (n == ntrans + 1) {\n            free(ntrans);\n            Metaph[0]='\\0';\n            return 1;           /* Return if zero characters        */\n      }\n      else  n_end = n;          /* Set end of string pointer        */\n\n      /*\n      ** Pad with '\\0's, front and rear\n      */\n\n      *n++ = '\\0';\n      *n   = '\\0';\n      n    = ntrans;\n      *n++ = '\\0';\n\n      /*\n      ** Check for PN, KN, GN, WR, WH, and X at start\n      */\n\n      switch (*n)\n      {\n      case 'P':\n      case 'K':\n      case 'G':\n            if ('N' == *(n + 1))\n                  *n++ = '\\0';\n            break;\n\n      case 'A':\n            if ('E' == *(n + 1))\n                  *n++ = '\\0';\n            break;\n\n      case 'W':\n            if ('R' == *(n + 1))\n                  *n++ = '\\0';\n            else if ('H' == *(n + 1))\n            {\n                  *(n + 1) = *n;\n                  *n++ = '\\0';\n            }\n            break;\n\n      case 'X':\n            *n = 'S';\n            break;\n      }\n\n      /*\n      ** Now loop through the string, stopping at the end of the string\n      ** or when the computed Metaphone code is max_phones characters long.\n      */\n\n      KSflag = 0;              /* State flag for KStranslation     */\n      for (metaph_end = Metaph + max_phones, n_start = n;\n            n <= n_end && Metaph < metaph_end; ++n)\n      {\n            if (KSflag)\n            {\n                  KSflag = 0;\n                  *Metaph++ = *n;\n            }\n            else\n            {\n                  /* Drop duplicates except for CC    */\n\n                  if (*(n - 1) == *n && *n != 'C')\n                        continue;\n\n                  /* Check for F J L M N R  or first letter vowel */\n\n                  if (same(*n) || (n == n_start && vowel(*n)))\n                        *Metaph++ = *n;\n                  else switch (*n)\n                  {\n                  case 'B':\n                        if (n < n_end || *(n - 1) != 'M')\n                              *Metaph++ = *n;\n                        break;\n\n                  case 'C':\n                        if (*(n - 1) != 'S' || !frontv(*(n + 1)))\n                        {\n                              if ('I' == *(n + 1) && 'A' == *(n + 2))\n                                    *Metaph++ = 'X';\n                              else if (frontv(*(n + 1)))\n                                    *Metaph++ = 'S';\n                              else if ('H' == *(n + 1))\n                                    *Metaph++ = ((n == n_start &&\n                                          !vowel(*(n + 2))) ||\n                                          'S' == *(n - 1)) ? 'K' : 'X';\n                              else  *Metaph++ = 'K';\n                        }\n                        break;\n\n                  case 'D':\n                        *Metaph++ = ('G' == *(n + 1) && frontv(*(n + 2))) ?\n                              'J' : 'T';\n                        break;\n\n                  case 'G':\n                        if ((*(n + 1) != 'H' || vowel(*(n + 2))) &&\n                              (*(n + 1) != 'N' || ((n + 1) < n_end &&\n                              (*(n + 2) != 'E' || *(n + 3) != 'D'))) &&\n                              (*(n - 1) != 'D' || !frontv(*(n + 1))))\n                        {\n                              *Metaph++ = (frontv(*(n + 1)) &&\n                                    *(n + 2) != 'G') ? 'J' : 'K';\n                        }\n                        else if ('H' == *(n + 1) && !noghf(*(n - 3)) &&\n                              *(n - 4) != 'H')\n                        {\n                              *Metaph++ = 'F';\n                        }\n                        break;\n\n                  case 'H':\n                        if (!varson(*(n - 1)) && (!vowel(*(n - 1)) ||\n                              vowel(*(n + 1))))\n                        {\n                              *Metaph++ = 'H';\n                        }\n                        break;\n\n                  case 'K':\n                        if (*(n - 1) != 'C')\n                              *Metaph++ = 'K';\n                        break;\n\n                  case 'P':\n                        *Metaph++ = ('H' == *(n + 1)) ? 'F' : 'P';\n                        break;\n\n                  case 'Q':\n                        *Metaph++ = 'K';\n                        break;\n\n                  case 'S':\n                        *Metaph++ = ('H' == *(n + 1) || ('I' == *(n + 1) &&\n                              ('O' == *(n + 2) || 'A' == *(n + 2)))) ?\n                              'X' : 'S';\n                        break;\n\n                  case 'T':\n                        if ('I' == *(n + 1) && ('O' == *(n + 2) ||\n                              'A' == *(n + 2)))\n                        {\n                              *Metaph++ = 'X';\n                        }\n                        else if ('H' == *(n + 1))\n                              *Metaph++ = 'O';\n                        else if (*(n + 1) != 'C' || *(n + 2) != 'H')\n                              *Metaph++ = 'T';\n                        break;\n\n                  case 'V':\n                        *Metaph++ = 'F';\n                        break;\n\n                  case 'W':\n                  case 'Y':\n                        if (vowel(*(n + 1)))\n                              *Metaph++ = *n;\n                        break;\n\n                  case 'X':\n                        if (n == n_start)\n                              *Metaph++ = 'S';\n                        else\n                        {\n                              *Metaph++ = 'K';\n                              KSflag = 1;\n                        }\n                        break;\n\n                  case 'Z':\n                        *Metaph++ = 'S';\n                        break;\n                  }\n            }\n      }\n\n      *Metaph = '\\0';\n      free(ntrans);\n      return strlen(metaph_start);\n}\n\n"
  },
  {
    "path": "src/shp2sqlite/Makefile",
    "content": "# **********************************************************************\n# * $Id: Makefile.in\n# *\n# * PostGIS - Spatial Types for PostgreSQL\n# * http://postgis.refractions.net\n# * Copyright 2008 Mark Cave-Ayland\n# *\n# * This is free software; you can redistribute and/or modify it under\n# * the terms of the GNU General Public Licence. See the COPYING file.\n# *\n# **********************************************************************\n\nCC=gcc\n\nCFLAGS=-g -O2  -fPIC -DPIC  -Wall -Wmissing-prototypes\n\n# Filenames with extension as determined by the OS\nSHP2SQLITE=shp2sqlite\nLIBLWGEOM=../liblwgeom/liblwgeom.a\n\n# iconv flags\nICONV_LDFLAGS=-lc\n\nall: $(SHP2SQLITE)\n\n$(LIBLWGEOM):\n\tmake -C ../liblwgeom\n\n$(SHP2SQLITE): shpopen.o dbfopen.o getopt.o shp2sqlite.o $(LIBLWGEOM)\n\n\t$(CC) -I/usr/include $(CFLAGS) $^ $(ICONV_LDFLAGS) -lm -o $@\n\ninstall: all\n\t@cp $(SHP2SQLITE) ../../build/\n\nclean:\n\t@rm -f *.o $(SHP2SQLITE)\n\n"
  },
  {
    "path": "src/shp2sqlite/Makefile.macosx",
    "content": "# **********************************************************************\n# * $Id: Makefile.in\n# *\n# * PostGIS - Spatial Types for PostgreSQL\n# * http://postgis.refractions.net\n# * Copyright 2008 Mark Cave-Ayland\n# *\n# * This is free software; you can redistribute and/or modify it under\n# * the terms of the GNU General Public Licence. See the COPYING file.\n# *\n# **********************************************************************\n#\n# This Makefile was modified by theduckylittle to build on Mac OS/X\n# with Iconv installed using brew. YMMV using ports and fink.\n#\n\nCC=gcc\n\nCFLAGS=-g -O2  -fPIC -DPIC  -Wall -Wmissing-prototypes\n\n# Filenames with extension as determined by the OS\nSHP2SQLITE=shp2sqlite\nLIBLWGEOM=../liblwgeom/liblwgeom.a\n\n# iconv flags\nICONV_LDFLAGS=-I/usr/local/Cellar/libiconv/1.14/include/ -L/usr/local/Cellar/libiconv/1.14/lib/ \nICONV_LDFLAGS=-liconv -lc\n\nall: $(SHP2SQLITE)\n\n$(LIBLWGEOM):\n\tmake -C ../liblwgeom\n\n$(SHP2SQLITE): shpopen.o dbfopen.o getopt.o shp2sqlite.o $(LIBLWGEOM)\n\t$(CC) $(CFLAGS) $(ICONV_LDFLAGS) -lm $^ -o $@\n\ninstall: all\n\t@cp $(SHP2SQLITE) ../../build/\n\nclean:\n\t@rm -f *.o $(SHP2SQLITE)\n\n"
  },
  {
    "path": "src/shp2sqlite/Makefile.nix",
    "content": "# **********************************************************************\n# * $Id: Makefile.in\n# *\n# * PostGIS - Spatial Types for PostgreSQL\n# * http://postgis.refractions.net\n# * Copyright 2008 Mark Cave-Ayland\n# *\n# * This is free software; you can redistribute and/or modify it under\n# * the terms of the GNU General Public Licence. See the COPYING file.\n# *\n# **********************************************************************\n\n\nCFLAGS=-g -O2  -fPIC -DPIC  -Wall -Wmissing-prototypes\n\n# Filenames with extension as determined by the OS\nSHP2SQLITE=shp2sqlite\nLIBLWGEOM=../liblwgeom/liblwgeom.a\n\n# iconv flags\nICONV_LDFLAGS=-lc\n\nall: $(SHP2SQLITE)\n\n$(LIBLWGEOM):\n\tmake -C ../liblwgeom\n\n$(SHP2SQLITE): shpopen.o dbfopen.o getopt.o shp2sqlite.o $(LIBLWGEOM)\n\t$(CC) $(CFLAGS) $^ $(ICONV_LDFLAGS) -lm -o $@ \n\ninstall: all\n\t@cp $(SHP2SQLITE) ../../bin\n\nclean:\n\t@rm -f *.o $(SHP2SQLITE)\n\n"
  },
  {
    "path": "src/shp2sqlite/Makefile.redhat",
    "content": "# **********************************************************************\n# * $Id: Makefile.in\n# *\n# * PostGIS - Spatial Types for PostgreSQL\n# * http://postgis.refractions.net\n# * Copyright 2008 Mark Cave-Ayland\n# *\n# * This is free software; you can redistribute and/or modify it under\n# * the terms of the GNU General Public Licence. See the COPYING file.\n# *\n# **********************************************************************\nCC=gcc\nCFLAGS=-g -O2  -fPIC -DPIC  -Wall -Wmissing-prototypes\n\n# Filenames with extension as determined by the OS\nSHP2SQLITE=shp2sqlite\nLIBLWGEOM=../liblwgeom/liblwgeom.a\n\n# iconv flags\nICONV_LDFLAGS=-lc\n\nall: $(SHP2SQLITE)\n\n$(LIBLWGEOM):\n\tmake -C ../liblwgeom\n\n$(SHP2SQLITE): shpopen.o dbfopen.o getopt.o shp2sqlite.o $(LIBLWGEOM)\n\t $(CC) $(CFLAGS) $^ $(ICONV_LDFLAGS) -lm -o $@\n\t\ninstall: all\n\t@cp $(SHP2SQLITE) ../../bin\n\nclean:\n\t@rm -f *.o $(SHP2SQLITE)\n\n"
  },
  {
    "path": "src/shp2sqlite/dbfopen.c",
    "content": "/******************************************************************************\n * $Id: dbfopen.c 3750 2009-02-19 21:12:22Z pramsey $\n *\n * Project:  Shapelib\n * Purpose:  Implementation of .dbf access API documented in dbf_api.html.\n * Author:   Frank Warmerdam, warmerdam@pobox.com\n *\n ******************************************************************************\n * Copyright (c) 1999, Frank Warmerdam\n *\n * This software is available under the following \"MIT Style\" license,\n * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This\n * option is discussed in more detail in shapelib.html.\n *\n * --\n * \n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included\n * in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n * DEALINGS IN THE SOFTWARE.\n ******************************************************************************\n *\n * $Log$\n * Revision 1.8  2006/01/16 10:42:57  strk\n * Added support for Bool and Date DBF<=>PGIS mapping\n *\n * Revision 1.7  2006/01/09 16:40:16  strk\n * ISO C90 comments, signedness mismatch fixes\n *\n * Revision 1.6  2003/12/01 20:52:00  strk\n * shapelib put in sync with gdal cvs\n *\n * Revision 1.52  2003/07/08 15:20:03  warmerda\n * avoid warnings about downcasting to unsigned char\n *\n * Revision 1.51  2003/07/08 13:50:15  warmerda\n * DBFIsAttributeNULL check for pszValue==NULL - bug 360\n *\n * Revision 1.50  2003/04/21 18:58:25  warmerda\n * ensure current record is flushed at same time as header is updated\n *\n * Revision 1.49  2003/04/21 18:30:37  warmerda\n * added header write/update public methods\n *\n * Revision 1.48  2003/03/10 14:51:27  warmerda\n * DBFWrite* calls now return FALSE if they have to truncate\n *\n * Revision 1.47  2002/11/20 03:32:22  warmerda\n * Ensure field name in DBFGetFieldIndex() is properly terminated.\n *\n * Revision 1.46  2002/10/09 13:10:21  warmerda\n * Added check that width is positive.\n *\n * Revision 1.45  2002/09/29 00:00:08  warmerda\n * added FTLogical and logical attribute read/write calls\n *\n * Revision 1.44  2002/05/07 13:46:11  warmerda\n * Added DBFWriteAttributeDirectly().\n *\n * Revision 1.43  2002/02/13 19:39:21  warmerda\n * Fix casting issues in DBFCloneEmpty().\n *\n * Revision 1.42  2002/01/15 14:36:07  warmerda\n * updated email address\n *\n * Revision 1.41  2002/01/15 14:31:49  warmerda\n * compute rather than copying nHeaderLength in DBFCloneEmpty()\n *\n * Revision 1.40  2002/01/09 04:32:35  warmerda\n * fixed to read correct amount of header\n *\n * Revision 1.39  2001/12/11 22:41:03  warmerda\n * improve io related error checking when reading header\n *\n * Revision 1.38  2001/11/28 16:07:31  warmerda\n * Cleanup to avoid compiler warnings as suggested by Richard Hash.\n *\n * Revision 1.37  2001/07/04 05:18:09  warmerda\n * do last fix properly\n *\n * Revision 1.36  2001/07/04 05:16:09  warmerda\n * fixed fieldname comparison in DBFGetFieldIndex\n *\n * Revision 1.35  2001/06/22 02:10:06  warmerda\n * fixed NULL shape support with help from Jim Matthews\n *\n * Revision 1.33  2001/05/31 19:20:13  warmerda\n * added DBFGetFieldIndex()\n *\n * Revision 1.32  2001/05/31 18:15:40  warmerda\n * Added support for NULL fields in DBF files\n *\n * Revision 1.31  2001/05/23 13:36:52  warmerda\n * added use of SHPAPI_CALL\n *\n * Revision 1.30  2000/12/05 14:43:38  warmerda\n * DBReadAttribute() white space trimming bug fix\n *\n * Revision 1.29  2000/10/05 14:36:44  warmerda\n * fix bug with writing very wide numeric fields\n *\n * Revision 1.28  2000/09/25 14:18:07  warmerda\n * Added some casts of strlen() return result to fix warnings on some\n * systems, as submitted by Daniel.\n *\n * Revision 1.27  2000/09/25 14:15:51  warmerda\n * added DBFGetNativeFieldType()\n *\n * Revision 1.26  2000/07/07 13:39:45  warmerda\n * removed unused variables, and added system include files\n *\n * Revision 1.25  2000/05/29 18:19:13  warmerda\n * avoid use of uchar, and adding casting fix\n *\n * Revision 1.24  2000/05/23 13:38:27  warmerda\n * Added error checks on return results of fread() and fseek().\n *\n * Revision 1.23  2000/05/23 13:25:49  warmerda\n * Avoid crashing if field or record are out of range in dbfread*attribute().\n *\n * Revision 1.22  1999/12/15 13:47:24  warmerda\n * Added stdlib.h to ensure that atof() is prototyped.\n *\n * Revision 1.21  1999/12/13 17:25:46  warmerda\n * Added support for upper case .DBF extention.\n *\n * Revision 1.20  1999/11/30 16:32:11  warmerda\n * Use atof() instead of sscanf().\n *\n * Revision 1.19  1999/11/05 14:12:04  warmerda\n * updated license terms\n *\n * Revision 1.18  1999/07/27 00:53:28  warmerda\n * ensure that whole old field value clear on write of string\n *\n * Revision 1.1  1999/07/05 18:58:07  warmerda\n * New\n *\n * Revision 1.17  1999/06/11 19:14:12  warmerda\n * Fixed some memory leaks.\n *\n * Revision 1.16  1999/06/11 19:04:11  warmerda\n * Remoted some unused variables.\n *\n * Revision 1.15  1999/05/11 03:19:28  warmerda\n * added new Tuple api, and improved extension handling - add from candrsn\n *\n * Revision 1.14  1999/05/04 15:01:48  warmerda\n * Added 'F' support.\n *\n * Revision 1.13  1999/03/23 17:38:59  warmerda\n * DBFAddField() now actually does return the new field number, or -1 if\n * it fails.\n *\n * Revision 1.12  1999/03/06 02:54:46  warmerda\n * Added logic to convert shapefile name to dbf filename in DBFOpen()\n * for convenience.\n *\n * Revision 1.11  1998/12/31 15:30:34  warmerda\n * Improved the interchangability of numeric and string attributes.  Add\n * white space trimming option for attributes.\n *\n * Revision 1.10  1998/12/03 16:36:44  warmerda\n * Use r+b instead of rb+ for binary access.\n *\n * Revision 1.9  1998/12/03 15:34:23  warmerda\n * Updated copyright message.\n *\n * Revision 1.8  1997/12/04 15:40:15  warmerda\n * Added newline character after field definitions.\n *\n * Revision 1.7  1997/03/06 14:02:10  warmerda\n * Ensure bUpdated is initialized.\n *\n * Revision 1.6  1996/02/12 04:54:41  warmerda\n * Ensure that DBFWriteAttribute() returns TRUE if it succeeds.\n *\n * Revision 1.5  1995/10/21  03:15:12  warmerda\n * Changed to use binary file access, and ensure that the\n * field name field is zero filled, and limited to 10 chars.\n *\n * Revision 1.4  1995/08/24  18:10:42  warmerda\n * Added use of SfRealloc() to avoid pre-ANSI realloc() functions such\n * as on the Sun.\n *\n * Revision 1.3  1995/08/04  03:15:16  warmerda\n * Fixed up header.\n *\n * Revision 1.2  1995/08/04  03:14:43  warmerda\n * Added header.\n */\n\n#include \"shapefil.h\"\n\n#include <math.h>\n#include <stdlib.h>\n#include <ctype.h>\n#include <string.h>\n\n#ifndef FALSE\n#  define FALSE\t\t0\n#  define TRUE\t\t1\n#endif\n\nstatic int\tnStringFieldLen = 0;\nstatic char * pszStringField = NULL;\n\n/************************************************************************/\n/*                             SfRealloc()                              */\n/*                                                                      */\n/*      A realloc cover function that will access a NULL pointer as     */\n/*      a valid input.                                                  */\n/************************************************************************/\n\nstatic void * SfRealloc( void * pMem, int nNewSize )\n\n{\n    if( pMem == NULL )\n        return( (void *) malloc(nNewSize) );\n    else\n        return( (void *) realloc(pMem,nNewSize) );\n}\n\n/************************************************************************/\n/*                           DBFWriteHeader()                           */\n/*                                                                      */\n/*      This is called to write out the file header, and field          */\n/*      descriptions before writing any actual data records.  This      */\n/*      also computes all the DBFDataSet field offset/size/decimals     */\n/*      and so forth values.                                            */\n/************************************************************************/\n\nstatic void DBFWriteHeader(DBFHandle psDBF)\n\n{\n    unsigned char\tabyHeader[XBASE_FLDHDR_SZ];\n    int\t\ti;\n\n    if( !psDBF->bNoHeader )\n        return;\n\n    psDBF->bNoHeader = FALSE;\n\n/* -------------------------------------------------------------------- */\n/*\tInitialize the file header information.\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    for( i = 0; i < XBASE_FLDHDR_SZ; i++ )\n        abyHeader[i] = 0;\n\n    abyHeader[0] = 0x03;\t\t/* memo field? - just copying \t*/\n\n    /* write out a dummy date */\n    abyHeader[1] = 95;\t\t\t/* YY */\n    abyHeader[2] = 7;\t\t\t/* MM */\n    abyHeader[3] = 26;\t\t\t/* DD */\n\n    /* record count preset at zero */\n\n    abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);\n    abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);\n    \n    abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);\n    abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);\n\n/* -------------------------------------------------------------------- */\n/*      Write the initial 32 byte file header, and all the field        */\n/*      descriptions.                                     \t\t*/\n/* -------------------------------------------------------------------- */\n    fseek( psDBF->fp, 0, 0 );\n    fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );\n    fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp );\n\n/* -------------------------------------------------------------------- */\n/*      Write out the newline character if there is room for it.        */\n/* -------------------------------------------------------------------- */\n    if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )\n    {\n        char\tcNewline;\n\n        cNewline = 0x0d;\n        fwrite( &cNewline, 1, 1, psDBF->fp );\n    }\n}\n\n/************************************************************************/\n/*                           DBFFlushRecord()                           */\n/*                                                                      */\n/*      Write out the current record if there is one.                   */\n/************************************************************************/\n\nstatic void DBFFlushRecord( DBFHandle psDBF )\n\n{\n    int\t\tnRecordOffset;\n\n    if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )\n    {\n\tpsDBF->bCurrentRecordModified = FALSE;\n\n\tnRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord \n\t                                             + psDBF->nHeaderLength;\n\n\tfseek( psDBF->fp, nRecordOffset, 0 );\n\tfwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );\n    }\n}\n\n/************************************************************************/\n/*                          DBFUpdateHeader()                           */\n/************************************************************************/\n\nvoid SHPAPI_CALL\nDBFUpdateHeader( DBFHandle psDBF )\n\n{\n    unsigned char\t\tabyFileHeader[32];\n\n    if( psDBF->bNoHeader )\n        DBFWriteHeader( psDBF );\n\n    DBFFlushRecord( psDBF );\n\n    fseek( psDBF->fp, 0, 0 );\n    fread( abyFileHeader, 32, 1, psDBF->fp );\n    \n    abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);\n    abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);\n    abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);\n    abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);\n    \n    fseek( psDBF->fp, 0, 0 );\n    fwrite( abyFileHeader, 32, 1, psDBF->fp );\n\n    fflush( psDBF->fp );\n}\n\n/************************************************************************/\n/*                              DBFOpen()                               */\n/*                                                                      */\n/*      Open a .dbf file.                                               */\n/************************************************************************/\n   \nDBFHandle SHPAPI_CALL\nDBFOpen( const char * pszFilename, const char * pszAccess )\n\n{\n    DBFHandle\t\tpsDBF;\n    unsigned char\t\t*pabyBuf;\n    int\t\t\tnFields, nHeadLen, nRecLen, iField, i;\n    char\t\t*pszBasename, *pszFullname;\n\n/* -------------------------------------------------------------------- */\n/*      We only allow the access strings \"rb\" and \"r+\".                  */\n/* -------------------------------------------------------------------- */\n    if( strcmp(pszAccess,\"r\") != 0 && strcmp(pszAccess,\"r+\") != 0 \n        && strcmp(pszAccess,\"rb\") != 0 && strcmp(pszAccess,\"rb+\") != 0\n        && strcmp(pszAccess,\"r+b\") != 0 )\n        return( NULL );\n\n    if( strcmp(pszAccess,\"r\") == 0 )\n        pszAccess = \"rb\";\n \n    if( strcmp(pszAccess,\"r+\") == 0 )\n        pszAccess = \"rb+\";\n\n/* -------------------------------------------------------------------- */\n/*\tCompute the base (layer) name.  If there is any extension\t*/\n/*\ton the passed in filename we will strip it off.\t\t\t*/\n/* -------------------------------------------------------------------- */\n    pszBasename = (char *) malloc(strlen(pszFilename)+5);\n    strcpy( pszBasename, pszFilename );\n    for( i = strlen(pszBasename)-1; \n\t i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'\n\t       && pszBasename[i] != '\\\\';\n\t i-- ) {}\n\n    if( pszBasename[i] == '.' )\n        pszBasename[i] = '\\0';\n\n    pszFullname = (char *) malloc(strlen(pszBasename) + 5);\n    sprintf( pszFullname, \"%s.dbf\", pszBasename );\n        \n    psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );\n    psDBF->fp = fopen( pszFullname, pszAccess );\n\n    if( psDBF->fp == NULL )\n    {\n        sprintf( pszFullname, \"%s.DBF\", pszBasename );\n        psDBF->fp = fopen(pszFullname, pszAccess );\n    }\n    \n    free( pszBasename );\n    free( pszFullname );\n    \n    if( psDBF->fp == NULL )\n    {\n        free( psDBF );\n        return( NULL );\n    }\n\n    psDBF->bNoHeader = FALSE;\n    psDBF->nCurrentRecord = -1;\n    psDBF->bCurrentRecordModified = FALSE;\n\n/* -------------------------------------------------------------------- */\n/*  Read Table Header info                                              */\n/* -------------------------------------------------------------------- */\n    pabyBuf = (unsigned char *) malloc(500);\n    if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )\n    {\n        fclose( psDBF->fp );\n        free( pabyBuf );\n        free( psDBF );\n        return NULL;\n    }\n\n    psDBF->nRecords = \n     pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;\n\n    psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;\n    psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256;\n    \n    psDBF->nFields = nFields = (nHeadLen - 32) / 32;\n\n    psDBF->pszCurrentRecord = (char *) malloc(nRecLen);\n\n/* -------------------------------------------------------------------- */\n/*  Read in Field Definitions                                           */\n/* -------------------------------------------------------------------- */\n    \n    pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);\n    psDBF->pszHeader = (char *) pabyBuf;\n\n    fseek( psDBF->fp, 32, 0 );\n    if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )\n    {\n        fclose( psDBF->fp );\n        free( pabyBuf );\n        free( psDBF );\n        return NULL;\n    }\n\n    psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);\n    psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);\n    psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);\n    psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);\n\n    for( iField = 0; iField < nFields; iField++ )\n    {\n\tunsigned char\t\t*pabyFInfo;\n\n\tpabyFInfo = pabyBuf+iField*32;\n\n\tif( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )\n\t{\n\t    psDBF->panFieldSize[iField] = pabyFInfo[16];\n\t    psDBF->panFieldDecimals[iField] = pabyFInfo[17];\n\t}\n\telse\n\t{\n\t    psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;\n\t    psDBF->panFieldDecimals[iField] = 0;\n\t}\n\n\tpsDBF->pachFieldType[iField] = (char) pabyFInfo[11];\n\tif( iField == 0 )\n\t    psDBF->panFieldOffset[iField] = 1;\n\telse\n\t    psDBF->panFieldOffset[iField] = \n\t      psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];\n    }\n\n    return( psDBF );\n}\n\n/************************************************************************/\n/*                              DBFClose()                              */\n/************************************************************************/\n\nvoid SHPAPI_CALL\nDBFClose(DBFHandle psDBF)\n{\n    static char eof = 0x1a;\n    char eof_test;\n\n/* -------------------------------------------------------------------- */\n/*      Write out header if not already written.                        */\n/* -------------------------------------------------------------------- */\n    if( psDBF->bNoHeader )\n        DBFWriteHeader( psDBF );\n\n    DBFFlushRecord( psDBF );\n\n/* -------------------------------------------------------------------- */\n/*      Update last access date, and number of records if we have\t*/\n/*\twrite access.                \t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    if( psDBF->bUpdated )\n        DBFUpdateHeader( psDBF );\n\n/* -------------------------------------------------------------------- */\n/*  Add the DBF end-of-file marker after the last record.               */\n/* -------------------------------------------------------------------- */\n\n    fseek(psDBF->fp, -1, SEEK_END);\n    fread(&eof_test, 1, 1, psDBF->fp);\n    if( eof_test != 0x1a ) /* no EOF exists, so write one */\n    {\n        fseek(psDBF->fp, 0, SEEK_END);\n        fwrite(&eof, 1, 1, psDBF->fp);\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Close, and free resources.                                      */\n/* -------------------------------------------------------------------- */\n    fclose( psDBF->fp );\n\n    if( psDBF->panFieldOffset != NULL )\n    {\n        free( psDBF->panFieldOffset );\n        free( psDBF->panFieldSize );\n        free( psDBF->panFieldDecimals );\n        free( psDBF->pachFieldType );\n    }\n\n    free( psDBF->pszHeader );\n    free( psDBF->pszCurrentRecord );\n\n    free( psDBF );\n\n    if( pszStringField != NULL )\n    {\n        free( pszStringField );\n        pszStringField = NULL;\n        nStringFieldLen = 0;\n    }\n}\n\n/************************************************************************/\n/*                             DBFCreate()                              */\n/*                                                                      */\n/*      Create a new .dbf file.                                         */\n/************************************************************************/\n\nDBFHandle SHPAPI_CALL\nDBFCreate( const char * pszFilename )\n\n{\n    DBFHandle\tpsDBF;\n    FILE\t*fp;\n    char\t*pszFullname, *pszBasename;\n    int\t\ti;\n\n/* -------------------------------------------------------------------- */\n/*\tCompute the base (layer) name.  If there is any extension\t*/\n/*\ton the passed in filename we will strip it off.\t\t\t*/\n/* -------------------------------------------------------------------- */\n    pszBasename = (char *) malloc(strlen(pszFilename)+5);\n    strcpy( pszBasename, pszFilename );\n    for( i = strlen(pszBasename)-1; \n\t i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'\n\t       && pszBasename[i] != '\\\\';\n\t i-- ) {}\n\n    if( pszBasename[i] == '.' )\n        pszBasename[i] = '\\0';\n\n    pszFullname = (char *) malloc(strlen(pszBasename) + 5);\n    sprintf( pszFullname, \"%s.dbf\", pszBasename );\n    free( pszBasename );\n\n/* -------------------------------------------------------------------- */\n/*      Create the file.                                                */\n/* -------------------------------------------------------------------- */\n    fp = fopen( pszFullname, \"wb\" );\n    if( fp == NULL )\n        return( NULL );\n\n    fputc( 0, fp );\n    fclose( fp );\n\n    fp = fopen( pszFullname, \"rb+\" );\n    if( fp == NULL )\n        return( NULL );\n\n    free( pszFullname );\n\n/* -------------------------------------------------------------------- */\n/*\tCreate the info structure.\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    psDBF = (DBFHandle) malloc(sizeof(DBFInfo));\n\n    psDBF->fp = fp;\n    psDBF->nRecords = 0;\n    psDBF->nFields = 0;\n    psDBF->nRecordLength = 1;\n    psDBF->nHeaderLength = 33;\n    psDBF->bUpdated = FALSE;\n    \n    psDBF->panFieldOffset = NULL;\n    psDBF->panFieldSize = NULL;\n    psDBF->panFieldDecimals = NULL;\n    psDBF->pachFieldType = NULL;\n    psDBF->pszHeader = NULL;\n\n    psDBF->nCurrentRecord = -1;\n    psDBF->bCurrentRecordModified = FALSE;\n    psDBF->pszCurrentRecord = NULL;\n\n    psDBF->bNoHeader = TRUE;\n\n    return( psDBF );\n}\n\n/************************************************************************/\n/*                            DBFAddField()                             */\n/*                                                                      */\n/*      Add a field to a newly created .dbf file before any records     */\n/*      are written.                                                    */\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFAddField(DBFHandle psDBF, const char * pszFieldName, \n            DBFFieldType eType, int nWidth, int nDecimals )\n\n{\n    char\t*pszFInfo;\n    int\t\ti;\n\n/* -------------------------------------------------------------------- */\n/*      Do some checking to ensure we can add records to this file.     */\n/* -------------------------------------------------------------------- */\n    if( psDBF->nRecords > 0 )\n        return( -1 );\n\n    if( !psDBF->bNoHeader )\n        return( -1 );\n\n    if( eType != FTDouble && nDecimals != 0 )\n        return( -1 );\n\n    if( nWidth < 1 )\n        return -1;\n\n/* -------------------------------------------------------------------- */\n/*      SfRealloc all the arrays larger to hold the additional field      */\n/*      information.                                                    */\n/* -------------------------------------------------------------------- */\n    psDBF->nFields++;\n\n    psDBF->panFieldOffset = (int *) \n      SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );\n\n    psDBF->panFieldSize = (int *) \n      SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );\n\n    psDBF->panFieldDecimals = (int *) \n      SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );\n\n    psDBF->pachFieldType = (char *) \n      SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );\n\n/* -------------------------------------------------------------------- */\n/*      Assign the new field information fields.                        */\n/* -------------------------------------------------------------------- */\n    psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;\n    psDBF->nRecordLength += nWidth;\n    psDBF->panFieldSize[psDBF->nFields-1] = nWidth;\n    psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;\n\n    if( eType == FTLogical )\n        psDBF->pachFieldType[psDBF->nFields-1] = 'L';\n    else if( eType == FTString )\n        psDBF->pachFieldType[psDBF->nFields-1] = 'C';\n    else if( eType == FTDate )\n        psDBF->pachFieldType[psDBF->nFields-1] = 'D';\n    else\n        psDBF->pachFieldType[psDBF->nFields-1] = 'N';\n\n/* -------------------------------------------------------------------- */\n/*      Extend the required header information.                         */\n/* -------------------------------------------------------------------- */\n    psDBF->nHeaderLength += 32;\n    psDBF->bUpdated = FALSE;\n\n    psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);\n\n    pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);\n\n    for( i = 0; i < 32; i++ )\n        pszFInfo[i] = '\\0';\n\n    if( (int) strlen(pszFieldName) < 10 )\n        strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));\n    else\n        strncpy( pszFInfo, pszFieldName, 10);\n\n    pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];\n\n    if( eType == FTString )\n    {\n        pszFInfo[16] = (unsigned char) (nWidth % 256);\n        pszFInfo[17] = (unsigned char) (nWidth / 256);\n    }\n    else\n    {\n        pszFInfo[16] = (unsigned char) nWidth;\n        pszFInfo[17] = (unsigned char) nDecimals;\n    }\n    \n/* -------------------------------------------------------------------- */\n/*      Make the current record buffer appropriately larger.            */\n/* -------------------------------------------------------------------- */\n    psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,\n\t\t\t\t\t       psDBF->nRecordLength);\n\n    return( psDBF->nFields-1 );\n}\n\n\n/************************************************************************/\n/*                        DBFReadSetup()                                */\n/*                                                                      */\n/*      Prep a record for reading.                                      */\n/************************************************************************/\n\nint DBFReadSetup(DBFHandle psDBF, int hEntity) \n{\n    int\t       \tnRecordOffset;\n\n/* -------------------------------------------------------------------- */\n/*      Verify selection.                                               */\n/* -------------------------------------------------------------------- */\n    if( hEntity < 0 || hEntity >= psDBF->nRecords )\n        return( 0 );\n\n/* -------------------------------------------------------------------- */\n/*\tHave we read the record?\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    if( psDBF->nCurrentRecord != hEntity )\n    {\n\tDBFFlushRecord( psDBF );\n\n\tnRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;\n\n\tif( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )\n        {\n            fprintf( stderr, \"fseek(%d) failed on DBF file.\\n\",\n                     nRecordOffset );\n            return 0;\n        }\n\n\tif( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, \n                   1, psDBF->fp ) != 1 )\n        {\n            fprintf( stderr, \"fread(%d) failed on DBF file.\\n\",\n                     psDBF->nRecordLength );\n            return 0;\n        }\n\n\tpsDBF->nCurrentRecord = hEntity;\n    }\n    \n    return 1;\n\n}\n\n\n/************************************************************************/\n/*                        DBFReadDeleted()                              */\n/*                                                                      */\n/*      Read whether a record is deleted.                               */\n/************************************************************************/\n\nint DBFReadDeleted(DBFHandle psDBF, int hEntity)\n{\n  unsigned char\t*pabyRec;\n  \n  if( ! DBFReadSetup( psDBF, hEntity) )\n    return 0;\n\n  /* get reference to current record */\n  pabyRec = (unsigned char *) psDBF->pszCurrentRecord;\n\n  /* 0x20 => not deleted, 0x24 => deleted */\n  return *pabyRec == 0x20 ? 0 : 1;\n\n}\n\n/************************************************************************/\n/*                          DBFReadAttribute()                          */\n/*                                                                      */\n/*      Read one of the attribute fields of a record.                   */\n/************************************************************************/\n\nstatic void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,\n                              char chReqType )\n\n{\n    unsigned char\t*pabyRec;\n    void\t*pReturnField = NULL;\n\n    static double dDoubleField;\n\n/* -------------------------------------------------------------------- */\n/*      Verify selection.                                               */\n/* -------------------------------------------------------------------- */\n    if( iField < 0 || iField >= psDBF->nFields )\n        return( NULL );\n\n    if( ! DBFReadSetup( psDBF, hEntity) )\n      return( NULL );\n\n    /* get reference to current record */\n    pabyRec = (unsigned char *) psDBF->pszCurrentRecord;\n\n/* -------------------------------------------------------------------- */\n/*\tEnsure our field buffer is large enough to hold this buffer.\t      */\n/* -------------------------------------------------------------------- */\n    if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )\n    {\n\t    nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;\n\t    pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);\n    }\n\n/* -------------------------------------------------------------------- */\n/*\tExtract the requested field.\t\t\t\t                              \t*/\n/* -------------------------------------------------------------------- */\n    strncpy( pszStringField, \n\t     ((const char *) pabyRec) + psDBF->panFieldOffset[iField],\n\t     psDBF->panFieldSize[iField] );\n    pszStringField[psDBF->panFieldSize[iField]] = '\\0';\n\n    pReturnField = pszStringField;\n\n/* -------------------------------------------------------------------- */\n/*      Decode the field.                                               */\n/* -------------------------------------------------------------------- */\n    if( chReqType == 'N' )\n    {\n      dDoubleField = atof(pszStringField);\n      pReturnField = &dDoubleField;\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Should we trim white space off the string attribute value?      */\n/* -------------------------------------------------------------------- */\n#ifdef TRIM_DBF_WHITESPACE\n    else\n    {\n        char\t*pchSrc, *pchDst;\n\n        pchDst = pchSrc = pszStringField;\n        while( *pchSrc == ' ' )\n            pchSrc++;\n\n        while( *pchSrc != '\\0' )\n            *(pchDst++) = *(pchSrc++);\n        *pchDst = '\\0';\n\n        while( pchDst != pszStringField && *(--pchDst) == ' ' )\n            *pchDst = '\\0';\n    }\n#endif\n    \n    return( pReturnField );\n}\n\n/************************************************************************/\n/*                        DBFReadIntAttribute()                         */\n/*                                                                      */\n/*      Read an integer attribute.                                      */\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )\n\n{\n    double\t*pdValue;\n\n    pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );\n\n    if( pdValue == NULL )\n        return 0;\n    else\n        return( (int) *pdValue );\n}\n\n/************************************************************************/\n/*                        DBFReadDoubleAttribute()                      */\n/*                                                                      */\n/*      Read a double attribute.                                        */\n/************************************************************************/\n\ndouble SHPAPI_CALL\nDBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )\n\n{\n    double\t*pdValue;\n\n    pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );\n\n    if( pdValue == NULL )\n        return 0.0;\n    else\n        return( *pdValue );\n}\n\n/************************************************************************/\n/*                        DBFReadStringAttribute()                      */\n/*                                                                      */\n/*      Read a string attribute.                                        */\n/************************************************************************/\n\nconst char SHPAPI_CALL1(*)\nDBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )\n\n{\n    return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );\n}\n\n/************************************************************************/\n/*                        DBFReadLogicalAttribute()                     */\n/*                                                                      */\n/*      Read a logical attribute.                                       */\n/************************************************************************/\n\nconst char SHPAPI_CALL1(*)\nDBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )\n\n{\n    return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );\n}\n\n/************************************************************************/\n/*                         DBFIsAttributeNULL()                         */\n/*                                                                      */\n/*      Return TRUE if value for field is NULL.                         */\n/*                                                                      */\n/*      Contributed by Jim Matthews.                                    */\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )\n\n{\n    const char\t*pszValue;\n\n    pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );\n\n    if( pszValue == NULL )\n        return TRUE;\n\n    switch(psDBF->pachFieldType[iField])\n    {\n      case 'N':\n      case 'F':\n        /* NULL numeric fields have value \"****************\" */\n        return pszValue[0] == '*';\n\n      case 'D':\n        /* NULL date fields have value \"00000000\" */\n        return (strncmp(pszValue,\"00000000\",8) == 0 || strlen(pszValue) == 0);\n\n      case 'L':\n        /* NULL boolean fields have value \"?\" */ \n        return pszValue[0] == '?';\n\n      default:\n        /* empty string fields are considered NULL */\n        return strlen(pszValue) == 0;\n    }\n}\n\n/************************************************************************/\n/*                          DBFGetFieldCount()                          */\n/*                                                                      */\n/*      Return the number of fields in this table.                      */\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFGetFieldCount( DBFHandle psDBF )\n\n{\n    return( psDBF->nFields );\n}\n\n/************************************************************************/\n/*                         DBFGetRecordCount()                          */\n/*                                                                      */\n/*      Return the number of records in this table.                     */\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFGetRecordCount( DBFHandle psDBF )\n\n{\n    return( psDBF->nRecords );\n}\n\n/************************************************************************/\n/*                          DBFGetFieldInfo()                           */\n/*                                                                      */\n/*      Return any requested information about the field.               */\n/************************************************************************/\n\nDBFFieldType SHPAPI_CALL\nDBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,\n                 int * pnWidth, int * pnDecimals )\n\n{\n    if( iField < 0 || iField >= psDBF->nFields )\n        return( FTInvalid );\n\n    if( pnWidth != NULL )\n        *pnWidth = psDBF->panFieldSize[iField];\n\n    if( pnDecimals != NULL )\n        *pnDecimals = psDBF->panFieldDecimals[iField];\n\n    if( pszFieldName != NULL )\n    {\n\tint\ti;\n\n\tstrncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );\n\tpszFieldName[11] = '\\0';\n\tfor( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )\n\t    pszFieldName[i] = '\\0';\n    }\n\n    if ( psDBF->pachFieldType[iField] == 'L' )\n\treturn( FTLogical);\n\n    else if( psDBF->pachFieldType[iField] == 'D'  )\n\treturn ( FTDate );\n\n    else if( psDBF->pachFieldType[iField] == 'N' \n             || psDBF->pachFieldType[iField] == 'F' )\n    {\n\tif( psDBF->panFieldDecimals[iField] > 0 )\n\t    return( FTDouble );\n\telse\n\t    return( FTInteger );\n    }\n    else\n    {\n\treturn( FTString );\n    }\n}\n\n/************************************************************************/\n/*                         DBFWriteAttribute()                          */\n/*\t\t\t\t\t\t\t\t\t*/\n/*\tWrite an attribute record to the file.\t\t\t\t*/\n/************************************************************************/\n\nstatic int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,\n\t\t\t     void * pValue )\n\n{\n    int\t       \tnRecordOffset, i, j, nRetResult = TRUE;\n    unsigned char\t*pabyRec;\n    char\tszSField[400], szFormat[20];\n\n/* -------------------------------------------------------------------- */\n/*\tIs this a valid record?\t\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    if( hEntity < 0 || hEntity > psDBF->nRecords )\n        return( FALSE );\n\n    if( psDBF->bNoHeader )\n        DBFWriteHeader(psDBF);\n\n/* -------------------------------------------------------------------- */\n/*      Is this a brand new record?                                     */\n/* -------------------------------------------------------------------- */\n    if( hEntity == psDBF->nRecords )\n    {\n\tDBFFlushRecord( psDBF );\n\n\tpsDBF->nRecords++;\n\tfor( i = 0; i < psDBF->nRecordLength; i++ )\n\t    psDBF->pszCurrentRecord[i] = ' ';\n\n\tpsDBF->nCurrentRecord = hEntity;\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Is this an existing record, but different than the last one     */\n/*      we accessed?                                                    */\n/* -------------------------------------------------------------------- */\n    if( psDBF->nCurrentRecord != hEntity )\n    {\n\tDBFFlushRecord( psDBF );\n\n\tnRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;\n\n\tfseek( psDBF->fp, nRecordOffset, 0 );\n\tfread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );\n\n\tpsDBF->nCurrentRecord = hEntity;\n    }\n\n    pabyRec = (unsigned char *) psDBF->pszCurrentRecord;\n\n    psDBF->bCurrentRecordModified = TRUE;\n    psDBF->bUpdated = TRUE;\n\n/* -------------------------------------------------------------------- */\n/*      Translate NULL value to valid DBF file representation.          */\n/*                                                                      */\n/*      Contributed by Jim Matthews.                                    */\n/* -------------------------------------------------------------------- */\n    if( pValue == NULL )\n    {\n        switch(psDBF->pachFieldType[iField])\n        {\n          case 'N':\n          case 'F':\n\t    /* NULL numeric fields have value \"****************\" */\n            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*', \n                    psDBF->panFieldSize[iField] );\n            break;\n\n          case 'D':\n\t    /* NULL date fields have value \"00000000\" */\n            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0', \n                    psDBF->panFieldSize[iField] );\n            break;\n\n          case 'L':\n\t    /* NULL boolean fields have value \"?\" */ \n            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?', \n                    psDBF->panFieldSize[iField] );\n            break;\n\n          default:\n            /* empty string fields are considered NULL */\n            memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\\0', \n                    psDBF->panFieldSize[iField] );\n            break;\n        }\n        return TRUE;\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Assign all the record fields.                                   */\n/* -------------------------------------------------------------------- */\n    switch( psDBF->pachFieldType[iField] )\n    {\n      case 'D':\n      case 'N':\n      case 'F':\n\tif( psDBF->panFieldDecimals[iField] == 0 )\n\t{\n            int\t\tnWidth = psDBF->panFieldSize[iField];\n\n            if( sizeof(szSField)-2 < nWidth )\n                nWidth = sizeof(szSField)-2;\n\n\t    sprintf( szFormat, \"%%%dd\", nWidth );\n\t    sprintf(szSField, szFormat, (int) *((double *) pValue) );\n\t    if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )\n            {\n\t        szSField[psDBF->panFieldSize[iField]] = '\\0';\n                nRetResult = FALSE;\n            }\n\n\t    strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),\n\t\t    szSField, strlen(szSField) );\n\t}\n\telse\n\t{\n            int\t\tnWidth = psDBF->panFieldSize[iField];\n\n            if( sizeof(szSField)-2 < nWidth )\n                nWidth = sizeof(szSField)-2;\n\n\t    sprintf( szFormat, \"%%%d.%df\", \n                     nWidth, psDBF->panFieldDecimals[iField] );\n\t    sprintf(szSField, szFormat, *((double *) pValue) );\n\t    if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )\n            {\n\t        szSField[psDBF->panFieldSize[iField]] = '\\0';\n                nRetResult = FALSE;\n            }\n\t    strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),\n\t\t    szSField, strlen(szSField) );\n\t}\n\tbreak;\n\n      case 'L':\n        if (psDBF->panFieldSize[iField] >= 1  && \n            (*(char*)pValue == 'F' || *(char*)pValue == 'T'))\n            *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;\n        break;\n\n      default:\n\tif( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )\n        {\n\t    j = psDBF->panFieldSize[iField];\n            nRetResult = FALSE;\n        }\n\telse\n        {\n            memset( pabyRec+psDBF->panFieldOffset[iField], ' ',\n                    psDBF->panFieldSize[iField] );\n\t    j = strlen((char *) pValue);\n        }\n\n\tstrncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),\n\t\t(char *) pValue, j );\n\tbreak;\n    }\n\n    return( nRetResult );\n}\n\n/************************************************************************/\n/*                     DBFWriteAttributeDirectly()                      */\n/*                                                                      */\n/*      Write an attribute record to the file, but without any          */\n/*      reformatting based on type.  The provided buffer is written     */\n/*      as is to the field position in the record.                      */\n/************************************************************************/\n\nint DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,\n                              const void * pValue )\n\n{\n    int\t       \tnRecordOffset, i, j;\n    unsigned char\t*pabyRec;\n\n/* -------------------------------------------------------------------- */\n/*\tIs this a valid record?\t\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    if( hEntity < 0 || hEntity > psDBF->nRecords )\n        return( FALSE );\n\n    if( psDBF->bNoHeader )\n        DBFWriteHeader(psDBF);\n\n/* -------------------------------------------------------------------- */\n/*      Is this a brand new record?                                     */\n/* -------------------------------------------------------------------- */\n    if( hEntity == psDBF->nRecords )\n    {\n\tDBFFlushRecord( psDBF );\n\n\tpsDBF->nRecords++;\n\tfor( i = 0; i < psDBF->nRecordLength; i++ )\n\t    psDBF->pszCurrentRecord[i] = ' ';\n\n\tpsDBF->nCurrentRecord = hEntity;\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Is this an existing record, but different than the last one     */\n/*      we accessed?                                                    */\n/* -------------------------------------------------------------------- */\n    if( psDBF->nCurrentRecord != hEntity )\n    {\n\tDBFFlushRecord( psDBF );\n\n\tnRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;\n\n\tfseek( psDBF->fp, nRecordOffset, 0 );\n\tfread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );\n\n\tpsDBF->nCurrentRecord = hEntity;\n    }\n\n    pabyRec = (unsigned char *) psDBF->pszCurrentRecord;\n\n/* -------------------------------------------------------------------- */\n/*      Assign all the record fields.                                   */\n/* -------------------------------------------------------------------- */\n    if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )\n        j = psDBF->panFieldSize[iField];\n    else\n    {\n        memset( pabyRec+psDBF->panFieldOffset[iField], ' ',\n                psDBF->panFieldSize[iField] );\n        j = strlen((char *) pValue);\n    }\n\n    strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),\n            (char *) pValue, j );\n\n    psDBF->bCurrentRecordModified = TRUE;\n    psDBF->bUpdated = TRUE;\n\n    return( TRUE );\n}\n\n/************************************************************************/\n/*                      DBFWriteDoubleAttribute()                       */\n/*                                                                      */\n/*      Write a double attribute.                                       */\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,\n                         double dValue )\n\n{\n    return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );\n}\n\n/************************************************************************/\n/*                      DBFWriteIntegerAttribute()                      */\n/*                                                                      */\n/*      Write a integer attribute.                                      */\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,\n                          int nValue )\n\n{\n    double\tdValue = nValue;\n\n    return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );\n}\n\n/************************************************************************/\n/*                      DBFWriteStringAttribute()                       */\n/*                                                                      */\n/*      Write a string attribute.                                       */\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,\n                         const char * pszValue )\n\n{\n    return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );\n}\n\n/************************************************************************/\n/*                      DBFWriteNULLAttribute()                         */\n/*                                                                      */\n/*      Write a string attribute.                                       */\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )\n\n{\n    return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );\n}\n\n/************************************************************************/\n/*                      DBFWriteLogicalAttribute()                      */\n/*                                                                      */\n/*      Write a logical attribute.                                      */\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,\n\t\t       const char lValue)\n\n{\n    return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );\n}\n\n/************************************************************************/\n/*                         DBFWriteTuple()                              */\n/*\t\t\t\t\t\t\t\t\t*/\n/*\tWrite an attribute record to the file.\t\t\t\t*/\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )\n\n{\n    int\t       \tnRecordOffset, i;\n    unsigned char\t*pabyRec;\n\n/* -------------------------------------------------------------------- */\n/*\tIs this a valid record?\t\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    if( hEntity < 0 || hEntity > psDBF->nRecords )\n        return( FALSE );\n\n    if( psDBF->bNoHeader )\n        DBFWriteHeader(psDBF);\n\n/* -------------------------------------------------------------------- */\n/*      Is this a brand new record?                                     */\n/* -------------------------------------------------------------------- */\n    if( hEntity == psDBF->nRecords )\n    {\n\tDBFFlushRecord( psDBF );\n\n\tpsDBF->nRecords++;\n\tfor( i = 0; i < psDBF->nRecordLength; i++ )\n\t    psDBF->pszCurrentRecord[i] = ' ';\n\n\tpsDBF->nCurrentRecord = hEntity;\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Is this an existing record, but different than the last one     */\n/*      we accessed?                                                    */\n/* -------------------------------------------------------------------- */\n    if( psDBF->nCurrentRecord != hEntity )\n    {\n\tDBFFlushRecord( psDBF );\n\n\tnRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;\n\n\tfseek( psDBF->fp, nRecordOffset, 0 );\n\tfread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );\n\n\tpsDBF->nCurrentRecord = hEntity;\n    }\n\n    pabyRec = (unsigned char *) psDBF->pszCurrentRecord;\n\n    memcpy ( pabyRec, pRawTuple,  psDBF->nRecordLength );\n\n    psDBF->bCurrentRecordModified = TRUE;\n    psDBF->bUpdated = TRUE;\n\n    return( TRUE );\n}\n\n/************************************************************************/\n/*                          DBFReadTuple()                              */\n/*                                                                      */\n/*      Read one of the attribute fields of a record.                   */\n/************************************************************************/\n\nconst char SHPAPI_CALL1(*)\nDBFReadTuple(DBFHandle psDBF, int hEntity )\n\n{\n    int\t       \tnRecordOffset;\n    unsigned char\t*pabyRec;\n    static char\t*pReturnTuple = NULL;\n\n    static int\tnTupleLen = 0;\n\n/* -------------------------------------------------------------------- */\n/*\tHave we read the record?\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    if( hEntity < 0 || hEntity >= psDBF->nRecords )\n        return( NULL );\n\n    if( psDBF->nCurrentRecord != hEntity )\n    {\n\tDBFFlushRecord( psDBF );\n\n\tnRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;\n\n\tfseek( psDBF->fp, nRecordOffset, 0 );\n\tfread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );\n\n\tpsDBF->nCurrentRecord = hEntity;\n    }\n\n    pabyRec = (unsigned char *) psDBF->pszCurrentRecord;\n\n    if ( nTupleLen < psDBF->nRecordLength) {\n      nTupleLen = psDBF->nRecordLength;\n      pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);\n    }\n    \n    memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );\n        \n    return( pReturnTuple );\n}\n\n/************************************************************************/\n/*                          DBFCloneEmpty()                              */\n/*                                                                      */\n/*      Read one of the attribute fields of a record.                   */\n/************************************************************************/\n\nDBFHandle SHPAPI_CALL\nDBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) \n{\n    DBFHandle\tnewDBF;\n\n   newDBF = DBFCreate ( pszFilename );\n   if ( newDBF == NULL ) return ( NULL ); \n   \n   newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );\n   memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );\n   \n   newDBF->nFields = psDBF->nFields;\n   newDBF->nRecordLength = psDBF->nRecordLength;\n   newDBF->nHeaderLength = 32 * (psDBF->nFields+1);\n    \n   newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); \n   memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );\n   newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );\n   memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );\n   newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );\n   memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );\n   newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );\n   memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );\n\n   newDBF->bNoHeader = TRUE;\n   newDBF->bUpdated = TRUE;\n   \n   DBFWriteHeader ( newDBF );\n   DBFClose ( newDBF );\n   \n   newDBF = DBFOpen ( pszFilename, \"rb+\" );\n\n   return ( newDBF );\n}\n\n/************************************************************************/\n/*                       DBFGetNativeFieldType()                        */\n/*                                                                      */\n/*      Return the DBase field type for the specified field.            */\n/*                                                                      */\n/*      Value can be one of: 'C' (String), 'D' (Date), 'F' (Float),     */\n/*                           'N' (Numeric, with or without decimal),    */\n/*                           'L' (Logical),                             */\n/*                           'M' (Memo: 10 digits .DBT block ptr)       */\n/************************************************************************/\n\nchar SHPAPI_CALL\nDBFGetNativeFieldType( DBFHandle psDBF, int iField )\n\n{\n    if( iField >=0 && iField < psDBF->nFields )\n        return psDBF->pachFieldType[iField];\n\n    return  ' ';\n}\n\n/************************************************************************/\n/*                            str_to_upper()                            */\n/************************************************************************/\n\nstatic void str_to_upper (char *string)\n{\n    int len;\n    short i = -1;\n\n    len = strlen (string);\n\n    while (++i < len)\n        if (isalpha(string[i]) && islower(string[i]))\n            string[i] = (char) toupper ((int)string[i]);\n}\n\n/************************************************************************/\n/*                          DBFGetFieldIndex()                          */\n/*                                                                      */\n/*      Get the index number for a field in a .dbf file.                */\n/*                                                                      */\n/*      Contributed by Jim Matthews.                                    */\n/************************************************************************/\n\nint SHPAPI_CALL\nDBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)\n\n{\n    char          name[12], name1[12], name2[12];\n    int           i;\n\n    strncpy(name1, pszFieldName,11);\n    name1[11] = '\\0';\n    str_to_upper(name1);\n\n    for( i = 0; i < DBFGetFieldCount(psDBF); i++ )\n    {\n        DBFGetFieldInfo( psDBF, i, name, NULL, NULL );\n        strncpy(name2,name,11);\n        str_to_upper(name2);\n\n        if(!strncmp(name1,name2,10))\n            return(i);\n    }\n    return(-1);\n}\n"
  },
  {
    "path": "src/shp2sqlite/getopt.c",
    "content": "\n/* This version of `getopt' appears to the caller like standard Unix `getopt'\n   but it behaves differently for the user, since it allows the user\n   to intersperse the options with the other arguments.\n\n   As `getopt' works, it permutes the elements of ARGV so that,\n   when it is done, all the options precede everything else.  Thus\n   all application programs are extended to handle flexible argument order.\n\n   Setting the environment variable POSIXLY_CORRECT disables permutation.\n   Then the behavior is completely standard.\n\n   GNU application programs can use a third alternative mode in which\n   they can distinguish the relative order of options and other arguments.  */\n\n#include <stdio.h>\n\n#include \"getopt.h\"\n\n\n/* For communication from `getopt' to the caller.\n   When `getopt' finds an option that takes an argument,\n   the argument value is returned here.\n   Also, when `ordering' is RETURN_IN_ORDER,\n   each non-option ARGV-element is returned here.  */\n\nchar *optarg = 0;\n\n/* Index in ARGV of the next element to be scanned.\n   This is used for communication to and from the caller\n   and for communication between successive calls to `getopt'.\n\n   On entry to `getopt', zero means this is the first call; initialize.\n\n   When `getopt' returns EOF, this is the index of the first of the\n   non-option elements that the caller should itself scan.\n\n   Otherwise, `optind' communicates from one call to the next\n   how much of ARGV has been scanned so far.  */\n\n/* XXX 1003.2 says this must be 1 before any call.  */\nint optind = 0;\n\n/* The next char to be scanned in the option-element\n   in which the last option character we returned was found.\n   This allows us to pick up the scan where we left off.\n\n   If this is zero, or a null string, it means resume the scan\n   by advancing to the next ARGV-element.  */\n\nstatic char *nextchar;\n\n/* Callers store zero here to inhibit the error message\n   for unrecognized options.  */\n\nint opterr = 1;\n\n/* Set to an option character which was unrecognized.\n   This must be initialized on some systems to avoid linking in the\n   system's own getopt implementation.  */\n\n#define BAD_OPTION '\\0'\nint optopt = BAD_OPTION;\n\n/* Describe how to deal with options that follow non-option ARGV-elements.\n\n   If the caller did not specify anything,\n   the default is REQUIRE_ORDER if the environment variable\n   POSIXLY_CORRECT is defined, PERMUTE otherwise.\n\n   REQUIRE_ORDER means don't recognize them as options;\n   stop option processing when the first non-option is seen.\n   This is what Unix does.\n   This mode of operation is selected by either setting the environment\n   variable POSIXLY_CORRECT, or using `+' as the first character\n   of the list of option characters.\n\n   PERMUTE is the default.  We permute the contents of ARGV as we scan,\n   so that eventually all the non-options are at the end.  This allows options\n   to be given in any order, even with programs that were not written to\n   expect this.\n\n   RETURN_IN_ORDER is an option available to programs that were written\n   to expect options and other ARGV-elements in any order and that care about\n   the ordering of the two.  We describe each non-option ARGV-element\n   as if it were the argument of an option with character code 1.\n   Using `-' as the first character of the list of option characters\n   selects this mode of operation.\n\n   The special argument `--' forces an end of option-scanning regardless\n   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only\n   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */\n\nstatic enum\n{\n  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER\n} ordering;\n\n#ifdef\t__GNU_LIBRARY__\n/* We want to avoid inclusion of string.h with non-GNU libraries\n   because there are many ways it can cause trouble.\n   On some systems, it contains special magic macros that don't work\n   in GCC.  */\n\n#include <string.h>\n#define\tmy_index\tstrchr\n#define\tmy_strlen\tstrlen\n#else\n\n/* Avoid depending on library functions or files\n   whose names are inconsistent.  */\n\n#if __STDC__ || defined(PROTO)\nextern int  strcmp (const char *s1, const char *s2);\nextern int  strncmp(const char *s1, const char *s2, int n);\n\nstatic int my_strlen(const char *s);\nstatic char *my_index (const char *str, int chr);\n#endif\n\nstatic int\nmy_strlen (str)\n     const char *str;\n{\n  int n = 0;\n  while (*str++)\n    n++;\n  return n;\n}\n\nstatic char *\nmy_index (str, chr)\n     const char *str;\n     int chr;\n{\n  while (*str)\n    {\n      if (*str == chr)\n\treturn (char *) str;\n      str++;\n    }\n  return 0;\n}\n\n#endif\t\t\t\t/* GNU C library.  */\n\nextern char *getenv(const char *name);\n\n/* Handle permutation of arguments.  */\n\n/* Describe the part of ARGV that contains non-options that have\n   been skipped.  `first_nonopt' is the index in ARGV of the first of them;\n   `last_nonopt' is the index after the last of them.  */\n\nstatic int first_nonopt;\nstatic int last_nonopt;\n\n/* Exchange two adjacent subsequences of ARGV.\n   One subsequence is elements [first_nonopt,last_nonopt)\n   which contains all the non-options that have been skipped so far.\n   The other is elements [last_nonopt,optind), which contains all\n   the options processed since those non-options were skipped.\n\n   `first_nonopt' and `last_nonopt' are relocated so that they describe\n   the new indices of the non-options in ARGV after they are moved.\n\n   To perform the swap, we first reverse the order of all elements. So\n   all options now come before all non options, but they are in the\n   wrong order. So we put back the options and non options in original\n   order by reversing them again. For example:\n       original input:      a b c -x -y\n       reverse all:         -y -x c b a\n       reverse options:     -x -y c b a\n       reverse non options: -x -y a b c\n*/\n\n#if __STDC__ || defined(PROTO)\nstatic void exchange (char **argv);\n#endif\n\nstatic void\nexchange (argv)\n     char **argv;\n{\n  char *temp, **first, **last;\n\n  /* Reverse all the elements [first_nonopt, optind) */\n  first = &argv[first_nonopt];\n  last  = &argv[optind-1];\n  while (first < last) {\n    temp = *first; *first = *last; *last = temp; first++; last--;\n  }\n  /* Put back the options in order */\n  first = &argv[first_nonopt];\n  first_nonopt += (optind - last_nonopt);\n  last  = &argv[first_nonopt - 1];\n  while (first < last) {\n    temp = *first; *first = *last; *last = temp; first++; last--;\n  }\n\n  /* Put back the non options in order */\n  first = &argv[first_nonopt];\n  last_nonopt = optind;\n  last  = &argv[last_nonopt-1];\n  while (first < last) {\n    temp = *first; *first = *last; *last = temp; first++; last--;\n  }\n}\n\n/* Scan elements of ARGV (whose length is ARGC) for option characters\n   given in OPTSTRING.\n\n   If an element of ARGV starts with '-', and is not exactly \"-\" or \"--\",\n   then it is an option element.  The characters of this element\n   (aside from the initial '-') are option characters.  If `getopt'\n   is called repeatedly, it returns successively each of the option characters\n   from each of the option elements.\n\n   If `getopt' finds another option character, it returns that character,\n   updating `optind' and `nextchar' so that the next call to `getopt' can\n   resume the scan with the following option character or ARGV-element.\n\n   If there are no more option characters, `getopt' returns `EOF'.\n   Then `optind' is the index in ARGV of the first ARGV-element\n   that is not an option.  (The ARGV-elements have been permuted\n   so that those that are not options now come last.)\n\n   OPTSTRING is a string containing the legitimate option characters.\n   If an option character is seen that is not listed in OPTSTRING,\n   return BAD_OPTION after printing an error message.  If you set `opterr' to\n   zero, the error message is suppressed but we still return BAD_OPTION.\n\n   If a char in OPTSTRING is followed by a colon, that means it wants an arg,\n   so the following text in the same ARGV-element, or the text of the following\n   ARGV-element, is returned in `optarg'.  Two colons mean an option that\n   wants an optional arg; if there is text in the current ARGV-element,\n   it is returned in `optarg', otherwise `optarg' is set to zero.\n\n   If OPTSTRING starts with `-' or `+', it requests different methods of\n   handling the non-option ARGV-elements.\n   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.\n\n   Long-named options begin with `--' instead of `-'.\n   Their names may be abbreviated as long as the abbreviation is unique\n   or is an exact match for some defined option.  If they have an\n   argument, it follows the option name in the same ARGV-element, separated\n   from the option name by a `=', or else the in next ARGV-element.\n   When `getopt' finds a long-named option, it returns 0 if that option's\n   `flag' field is nonzero, the value of the option's `val' field\n   if the `flag' field is zero.\n\n   The elements of ARGV aren't really const, because we permute them.\n   But we pretend they're const in the prototype to be compatible\n   with other systems.\n\n   LONGOPTS is a vector of `struct option' terminated by an\n   element containing a name which is zero.\n\n   LONGIND returns the index in LONGOPT of the long-named option found.\n   It is only valid when a long-named option has been found by the most\n   recent call.\n\n   If LONG_ONLY is nonzero, '-' as well as '--' can introduce\n   long-named options.  */\n\nint\n_pgis_getopt_internal (argc, argv, optstring, longopts, longind, long_only)\n     int argc;\n     char *const *argv;\n     const char *optstring;\n     const struct option *longopts;\n     int *longind;\n     int long_only;\n{\n  int option_index;\n\n  optarg = 0;\n\n  /* Initialize the internal data when the first call is made.\n     Start processing options with ARGV-element 1 (since ARGV-element 0\n     is the program name); the sequence of previously skipped\n     non-option ARGV-elements is empty.  */\n\n  if (optind == 0)\n    {\n      first_nonopt = last_nonopt = optind = 1;\n\n      nextchar = NULL;\n\n      /* Determine how to handle the ordering of options and nonoptions.  */\n\n      if (optstring[0] == '-')\n\t{\n\t  ordering = RETURN_IN_ORDER;\n\t  ++optstring;\n\t}\n      else if (optstring[0] == '+')\n\t{\n\t  ordering = REQUIRE_ORDER;\n\t  ++optstring;\n\t}\n      else if (getenv (\"POSIXLY_CORRECT\") != NULL)\n\tordering = REQUIRE_ORDER;\n      else\n\tordering = PERMUTE;\n    }\n\n  if (nextchar == NULL || *nextchar == '\\0')\n    {\n      if (ordering == PERMUTE)\n\t{\n\t  /* If we have just processed some options following some non-options,\n\t     exchange them so that the options come first.  */\n\n\t  if (first_nonopt != last_nonopt && last_nonopt != optind)\n\t    exchange ((char **) argv);\n\t  else if (last_nonopt != optind)\n\t    first_nonopt = optind;\n\n\t  /* Now skip any additional non-options\n\t     and extend the range of non-options previously skipped.  */\n\n\t  while (optind < argc\n\t\t && (argv[optind][0] != '-' || argv[optind][1] == '\\0')\n#ifdef GETOPT_COMPAT\n\t\t && (longopts == NULL\n\t\t     || argv[optind][0] != '+' || argv[optind][1] == '\\0')\n#endif\t\t\t\t/* GETOPT_COMPAT */\n\t\t )\n\t    optind++;\n\t  last_nonopt = optind;\n\t}\n\n      /* Special ARGV-element `--' means premature end of options.\n\t Skip it like a null option,\n\t then exchange with previous non-options as if it were an option,\n\t then skip everything else like a non-option.  */\n\n      if (optind != argc && !strcmp (argv[optind], \"--\"))\n\t{\n\t  optind++;\n\n\t  if (first_nonopt != last_nonopt && last_nonopt != optind)\n\t    exchange ((char **) argv);\n\t  else if (first_nonopt == last_nonopt)\n\t    first_nonopt = optind;\n\t  last_nonopt = argc;\n\n\t  optind = argc;\n\t}\n\n      /* If we have done all the ARGV-elements, stop the scan\n\t and back over any non-options that we skipped and permuted.  */\n\n      if (optind == argc)\n\t{\n\t  /* Set the next-arg-index to point at the non-options\n\t     that we previously skipped, so the caller will digest them.  */\n\t  if (first_nonopt != last_nonopt)\n\t    optind = first_nonopt;\n\t  return EOF;\n\t}\n\n      /* If we have come to a non-option and did not permute it,\n\t either stop the scan or describe it to the caller and pass it by.  */\n\n      if ((argv[optind][0] != '-' || argv[optind][1] == '\\0')\n#ifdef GETOPT_COMPAT\n\t  && (longopts == NULL\n\t      || argv[optind][0] != '+' || argv[optind][1] == '\\0')\n#endif\t\t\t\t/* GETOPT_COMPAT */\n\t  )\n\t{\n\t  if (ordering == REQUIRE_ORDER)\n\t    return EOF;\n\t  optarg = argv[optind++];\n\t  return 1;\n\t}\n\n      /* We have found another option-ARGV-element.\n\t Start decoding its characters.  */\n\n      nextchar = (argv[optind] + 1\n\t\t  + (longopts != NULL && argv[optind][1] == '-'));\n    }\n\n  if (longopts != NULL\n      && ((argv[optind][0] == '-'\n\t   && (argv[optind][1] == '-' || long_only))\n#ifdef GETOPT_COMPAT\n\t  || argv[optind][0] == '+'\n#endif\t\t\t\t/* GETOPT_COMPAT */\n\t  ))\n    {\n      const struct option *p;\n      char *s = nextchar;\n      int exact = 0;\n      int ambig = 0;\n      const struct option *pfound = NULL;\n      int indfound = 0;\n\n      while (*s && *s != '=')\n\ts++;\n\n      /* Test all options for either exact match or abbreviated matches.  */\n      for (p = longopts, option_index = 0; p->name;\n\t   p++, option_index++)\n\tif (!strncmp (p->name, nextchar, s - nextchar))\n\t  {\n\t    if (s - nextchar == my_strlen (p->name))\n\t      {\n\t\t/* Exact match found.  */\n\t\tpfound = p;\n\t\tindfound = option_index;\n\t\texact = 1;\n\t\tbreak;\n\t      }\n\t    else if (pfound == NULL)\n\t      {\n\t\t/* First nonexact match found.  */\n\t\tpfound = p;\n\t\tindfound = option_index;\n\t      }\n\t    else\n\t      /* Second nonexact match found.  */\n\t      ambig = 1;\n\t  }\n\n      if (ambig && !exact)\n\t{\n\t  if (opterr)\n\t    fprintf (stderr, \"%s: option `%s' is ambiguous\\n\",\n\t\t     argv[0], argv[optind]);\n\t  nextchar += my_strlen (nextchar);\n\t  optind++;\n\t  return BAD_OPTION;\n\t}\n\n      if (pfound != NULL)\n\t{\n\t  option_index = indfound;\n\t  optind++;\n\t  if (*s)\n\t    {\n\t      /* Don't test has_arg with >, because some C compilers don't\n\t\t allow it to be used on enums.  */\n\t      if (pfound->has_arg)\n\t\toptarg = s + 1;\n\t      else\n\t\t{\n\t\t  if (opterr)\n\t\t    {\n\t\t      if (argv[optind - 1][1] == '-')\n\t\t\t/* --option */\n\t\t\tfprintf (stderr,\n\t\t\t\t \"%s: option `--%s' doesn't allow an argument\\n\",\n\t\t\t\t argv[0], pfound->name);\n\t\t      else\n\t\t\t/* +option or -option */\n\t\t\tfprintf (stderr,\n\t\t\t     \"%s: option `%c%s' doesn't allow an argument\\n\",\n\t\t\t     argv[0], argv[optind - 1][0], pfound->name);\n\t\t    }\n\t\t  nextchar += my_strlen (nextchar);\n\t\t  return BAD_OPTION;\n\t\t}\n\t    }\n\t  else if (pfound->has_arg == 1)\n\t    {\n\t      if (optind < argc)\n\t\toptarg = argv[optind++];\n\t      else\n\t\t{\n\t\t  if (opterr)\n\t\t    fprintf (stderr, \"%s: option `%s' requires an argument\\n\",\n\t\t\t     argv[0], argv[optind - 1]);\n\t\t  nextchar += my_strlen (nextchar);\n\t\t  return optstring[0] == ':' ? ':' : BAD_OPTION;\n\t\t}\n\t    }\n\t  nextchar += my_strlen (nextchar);\n\t  if (longind != NULL)\n\t    *longind = option_index;\n\t  if (pfound->flag)\n\t    {\n\t      *(pfound->flag) = pfound->val;\n\t      return 0;\n\t    }\n\t  return pfound->val;\n\t}\n      /* Can't find it as a long option.  If this is not getopt_long_only,\n\t or the option starts with '--' or is not a valid short\n\t option, then it's an error.\n\t Otherwise interpret it as a short option.  */\n      if (!long_only || argv[optind][1] == '-'\n#ifdef GETOPT_COMPAT\n\t  || argv[optind][0] == '+'\n#endif\t\t\t\t/* GETOPT_COMPAT */\n\t  || my_index (optstring, *nextchar) == NULL)\n\t{\n\t  if (opterr)\n\t    {\n\t      if (argv[optind][1] == '-')\n\t\t/* --option */\n\t\tfprintf (stderr, \"%s: unrecognized option `--%s'\\n\",\n\t\t\t argv[0], nextchar);\n\t      else\n\t\t/* +option or -option */\n\t\tfprintf (stderr, \"%s: unrecognized option `%c%s'\\n\",\n\t\t\t argv[0], argv[optind][0], nextchar);\n\t    }\n\t  nextchar = (char *) \"\";\n\t  optind++;\n\t  return BAD_OPTION;\n\t}\n    }\n\n  /* Look at and handle the next option-character.  */\n\n  {\n    char c = *nextchar++;\n    char *temp = my_index (optstring, c);\n\n    /* Increment `optind' when we start to process its last character.  */\n    if (*nextchar == '\\0')\n      ++optind;\n\n    if (temp == NULL || c == ':')\n      {\n\tif (opterr)\n\t  {\n#if 0\n\t    if (c < 040 || c >= 0177)\n\t      fprintf (stderr, \"%s: unrecognized option, character code 0%o\\n\",\n\t\t       argv[0], c);\n\t    else\n\t      fprintf (stderr, \"%s: unrecognized option `-%c'\\n\", argv[0], c);\n#else\n\t    /* 1003.2 specifies the format of this message.  */\n\t    fprintf (stderr, \"%s: illegal option -- %c\\n\", argv[0], c);\n#endif\n\t  }\n\toptopt = c;\n\treturn BAD_OPTION;\n      }\n    if (temp[1] == ':')\n      {\n\tif (temp[2] == ':')\n\t  {\n\t    /* This is an option that accepts an argument optionally.  */\n\t    if (*nextchar != '\\0')\n\t      {\n\t\toptarg = nextchar;\n\t\toptind++;\n\t      }\n\t    else\n\t      optarg = 0;\n\t    nextchar = NULL;\n\t  }\n\telse\n\t  {\n\t    /* This is an option that requires an argument.  */\n\t    if (*nextchar != '\\0')\n\t      {\n\t\toptarg = nextchar;\n\t\t/* If we end this ARGV-element by taking the rest as an arg,\n\t\t   we must advance to the next element now.  */\n\t\toptind++;\n\t      }\n\t    else if (optind == argc)\n\t      {\n\t\tif (opterr)\n\t\t  {\n#if 0\n\t\t    fprintf (stderr, \"%s: option `-%c' requires an argument\\n\",\n\t\t\t     argv[0], c);\n#else\n\t\t    /* 1003.2 specifies the format of this message.  */\n\t\t    fprintf (stderr, \"%s: option requires an argument -- %c\\n\",\n\t\t\t     argv[0], c);\n#endif\n\t\t  }\n\t\toptopt = c;\n\t\tif (optstring[0] == ':')\n\t\t  c = ':';\n\t\telse\n\t\t  c = BAD_OPTION;\n\t      }\n\t    else\n\t      /* We already incremented `optind' once;\n\t\t increment it again when taking next ARGV-elt as argument.  */\n\t      optarg = argv[optind++];\n\t    nextchar = NULL;\n\t  }\n      }\n    return c;\n  }\n}\n\nint\npgis_getopt (argc, argv, optstring)\n     int argc;\n     char *const *argv;\n     const char *optstring;\n{\n  return _pgis_getopt_internal (argc, argv, optstring,\n\t\t\t   (const struct option *) 0,\n\t\t\t   (int *) 0,\n\t\t\t   0);\n}\n\nint\npgis_getopt_long (argc, argv, options, long_options, opt_index)\n     int argc;\n     char *const *argv;\n     const char *options;\n     const struct option *long_options;\n     int *opt_index;\n{\n  return _pgis_getopt_internal (argc, argv, options, long_options, opt_index, 0);\n}\n\n/* #endif\t  _LIBC or not __GNU_LIBRARY__.  */\n\n#ifdef TEST\n\n/* Compile with -DTEST to make an executable for use in testing\n   the above definition of `getopt'.  */\n\nint\nmain (argc, argv)\n     int argc;\n     char **argv;\n{\n  int c;\n  int digit_optind = 0;\n\n  while (1)\n    {\n      int this_option_optind = optind ? optind : 1;\n\n      c = pgis_getopt (argc, argv, \"abc:d:0123456789\");\n      if (c == EOF)\n\tbreak;\n\n      switch (c)\n\t{\n\tcase '0':\n\tcase '1':\n\tcase '2':\n\tcase '3':\n\tcase '4':\n\tcase '5':\n\tcase '6':\n\tcase '7':\n\tcase '8':\n\tcase '9':\n\t  if (digit_optind != 0 && digit_optind != this_option_optind)\n\t    printf (\"digits occur in two different argv-elements.\\n\");\n\t  digit_optind = this_option_optind;\n\t  printf (\"option %c\\n\", c);\n\t  break;\n\n\tcase 'a':\n\t  printf (\"option a\\n\");\n\t  break;\n\n\tcase 'b':\n\t  printf (\"option b\\n\");\n\t  break;\n\n\tcase 'c':\n\t  printf (\"option c with value `%s'\\n\", optarg);\n\t  break;\n\n\tcase BAD_OPTION:\n\t  break;\n\n\tdefault:\n\t  printf (\"?? getopt returned character code 0%o ??\\n\", c);\n\t}\n    }\n\n  if (optind < argc)\n    {\n      printf (\"non-option ARGV-elements: \");\n      while (optind < argc)\n\tprintf (\"%s \", argv[optind++]);\n      printf (\"\\n\");\n    }\n\n  exit (0);\n}\n\n#endif /* TEST */\n"
  },
  {
    "path": "src/shp2sqlite/getopt.h",
    "content": "/* Declarations for getopt.\n   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.\n\n   This program is free software; you can redistribute it and/or modify it\n   under the terms of the GNU General Public License as published by the\n   Free Software Foundation; either version 2, or (at your option) any\n   later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */\n\n#ifndef _GETOPT_H\n#define _GETOPT_H 1\n\n#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n/* For communication from `getopt' to the caller.\n   When `getopt' finds an option that takes an argument,\n   the argument value is returned here.\n   Also, when `ordering' is RETURN_IN_ORDER,\n   each non-option ARGV-element is returned here.  */\n\nextern char *optarg;\n\n/* Index in ARGV of the next element to be scanned.\n   This is used for communication to and from the caller\n   and for communication between successive calls to `getopt'.\n\n   On entry to `getopt', zero means this is the first call; initialize.\n\n   When `getopt' returns EOF, this is the index of the first of the\n   non-option elements that the caller should itself scan.\n\n   Otherwise, `optind' communicates from one call to the next\n   how much of ARGV has been scanned so far.  */\n\nextern int optind;\n\n/* Callers store zero here to inhibit the error message `getopt' prints\n   for unrecognized options.  */\n\nextern int opterr;\n\n/* Set to an option character which was unrecognized.  */\n\nextern int optopt;\n\n/* Describe the long-named options requested by the application.\n   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector\n   of `struct option' terminated by an element containing a name which is\n   zero.\n\n   The field `has_arg' is:\n   no_argument\t\t(or 0) if the option does not take an argument,\n   required_argument\t(or 1) if the option requires an argument,\n   optional_argument \t(or 2) if the option takes an optional argument.\n\n   If the field `flag' is not NULL, it points to a variable that is set\n   to the value given in the field `val' when the option is found, but\n   left unchanged if the option is not found.\n\n   To have a long-named option do something other than set an `int' to\n   a compiled-in constant, such as set a value from `optarg', set the\n   option's `flag' field to zero and its `val' field to a nonzero\n   value (the equivalent single-letter option character, if there is\n   one).  For long options that have a zero `flag' field, `getopt'\n   returns the contents of the `val' field.  */\n\nstruct option\n{\n#if\t__STDC__\n  const char *name;\n#else\n  char *name;\n#endif\n  /* has_arg can't be an enum because some compilers complain about\n     type mismatches in all the code that assumes it is an int.  */\n  int has_arg;\n  int *flag;\n  int val;\n};\n\n/* Names for the values of the `has_arg' field of `struct option'.  */\n\n#define\tno_argument\t\t0\n#define required_argument\t1\n#define optional_argument\t2\n\n#if __STDC__ || defined(PROTO)\n#if defined(__GNU_LIBRARY__)\n/* Many other libraries have conflicting prototypes for getopt, with\n   differences in the consts, in stdlib.h.  To avoid compilation\n   errors, only prototype getopt for the GNU C library.  */\nextern int pgis_getopt (int argc, char *const *argv, const char *shortopts);\n#endif /* not __GNU_LIBRARY__ */\nextern int pgis_getopt_long (int argc, char *const *argv, const char *shortopts,\n\t\t        const struct option *longopts, int *longind);\nextern int pgis_getopt_long_only (int argc, char *const *argv,\n\t\t\t     const char *shortopts,\n\t\t             const struct option *longopts, int *longind);\n\n/* Internal only.  Users should not call this directly.  */\nextern int _pgis_getopt_internal (int argc, char *const *argv,\n\t\t\t     const char *shortopts,\n\t\t             const struct option *longopts, int *longind,\n\t\t\t     int long_only);\n#else /* not __STDC__ */\nextern int pgis_getopt ();\nextern int pgis_getopt_long ();\nextern int pgis_getopt_long_only ();\n\nextern int _pgis_getopt_internal ();\n#endif /* not __STDC__ */\n\n#ifdef\t__cplusplus\n}\n#endif\n\n#endif /* _GETOPT_H */\n"
  },
  {
    "path": "src/shp2sqlite/shapefil.h",
    "content": "#ifndef _SHAPEFILE_H_INCLUDED\n#define _SHAPEFILE_H_INCLUDED\n\n/******************************************************************************\n * $Id: shapefil.h 2785 2008-05-27 15:08:20Z mcayland $\n *\n * Project:  Shapelib\n * Purpose:  Primary include file for Shapelib.\n * Author:   Frank Warmerdam, warmerdam@pobox.com\n *\n ******************************************************************************\n * Copyright (c) 1999, Frank Warmerdam\n *\n * This software is available under the following \"MIT Style\" license,\n * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This\n * option is discussed in more detail in shapelib.html.\n *\n * --\n * \n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included\n * in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n * DEALINGS IN THE SOFTWARE.\n ******************************************************************************\n *\n * $Log$\n * Revision 1.5  2006/01/16 10:42:58  strk\n * Added support for Bool and Date DBF<=>PGIS mapping\n *\n * Revision 1.4  2003/12/01 20:52:00  strk\n * shapelib put in sync with gdal cvs\n *\n * Revision 1.27  2003/04/21 18:30:37  warmerda\n * added header write/update public methods\n *\n * Revision 1.26  2002/09/29 00:00:08  warmerda\n * added FTLogical and logical attribute read/write calls\n *\n * Revision 1.25  2002/05/07 13:46:30  warmerda\n * added DBFWriteAttributeDirectly().\n *\n * Revision 1.24  2002/04/10 16:59:54  warmerda\n * added SHPRewindObject\n *\n * Revision 1.23  2002/01/15 14:36:07  warmerda\n * updated email address\n *\n * Revision 1.22  2002/01/15 14:32:00  warmerda\n * try to improve SHPAPI_CALL docs\n *\n * Revision 1.21  2001/11/01 16:29:55  warmerda\n * move pabyRec into SHPInfo for thread safety\n *\n * Revision 1.20  2001/07/20 13:06:02  warmerda\n * fixed SHPAPI attribute for SHPTreeFindLikelyShapes\n *\n * Revision 1.19  2001/05/31 19:20:13  warmerda\n * added DBFGetFieldIndex()\n *\n * Revision 1.18  2001/05/31 18:15:40  warmerda\n * Added support for NULL fields in DBF files\n *\n * Revision 1.17  2001/05/23 13:36:52  warmerda\n * added use of SHPAPI_CALL\n *\n * Revision 1.16  2000/09/25 14:15:59  warmerda\n * added DBFGetNativeFieldType()\n *\n * Revision 1.15  2000/02/16 16:03:51  warmerda\n * added null shape support\n *\n * Revision 1.14  1999/11/05 14:12:05  warmerda\n * updated license terms\n *\n * Revision 1.13  1999/06/02 18:24:21  warmerda\n * added trimming code\n *\n * Revision 1.12  1999/06/02 17:56:12  warmerda\n * added quad'' subnode support for trees\n *\n * Revision 1.11  1999/05/18 19:11:11  warmerda\n * Added example searching capability\n *\n * Revision 1.10  1999/05/18 17:49:38  warmerda\n * added initial quadtree support\n *\n * Revision 1.9  1999/05/11 03:19:28  warmerda\n * added new Tuple api, and improved extension handling - add from candrsn\n *\n * Revision 1.8  1999/03/23 17:22:27  warmerda\n * Added extern \"C\" protection for C++ users of shapefil.h.\n *\n * Revision 1.7  1998/12/31 15:31:07  warmerda\n * Added the TRIM_DBF_WHITESPACE and DISABLE_MULTIPATCH_MEASURE options.\n *\n * Revision 1.6  1998/12/03 15:48:15  warmerda\n * Added SHPCalculateExtents().\n *\n * Revision 1.5  1998/11/09 20:57:16  warmerda\n * Altered SHPGetInfo() call.\n *\n * Revision 1.4  1998/11/09 20:19:33  warmerda\n * Added 3D support, and use of SHPObject.\n *\n * Revision 1.3  1995/08/23 02:24:05  warmerda\n * Added support for reading bounds.\n *\n * Revision 1.2  1995/08/04  03:17:39  warmerda\n * Added header.\n *\n */\n\n#include <stdio.h>\n\n#ifdef USE_DBMALLOC\n#include <dbmalloc.h>\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/************************************************************************/\n/*                        Configuration options.                        */\n/************************************************************************/\n\n/* -------------------------------------------------------------------- */\n/*      Should the DBFReadStringAttribute() strip leading and           */\n/*      trailing white space?                                           */\n/* -------------------------------------------------------------------- */\n#define TRIM_DBF_WHITESPACE\n\n/* -------------------------------------------------------------------- */\n/*      Should we write measure values to the Multipatch object?        */\n/*      Reportedly ArcView crashes if we do write it, so for now it     */\n/*      is disabled.                                                    */\n/* -------------------------------------------------------------------- */\n#define DISABLE_MULTIPATCH_MEASURE\n\n/* -------------------------------------------------------------------- */\n/*      SHPAPI_CALL                                                     */\n/*                                                                      */\n/*      The following two macros are present to allow forcing           */\n/*      various calling conventions on the Shapelib API.                */\n/*                                                                      */\n/*      To force __stdcall conventions (needed to call Shapelib         */\n/*      from Visual Basic and/or Dephi I believe) the makefile could    */\n/*      be modified to define:                                          */\n/*                                                                      */\n/*        /DSHPAPI_CALL=__stdcall                                       */\n/*                                                                      */\n/*      If it is desired to force export of the Shapelib API without    */\n/*      using the shapelib.def file, use the following definition.      */\n/*                                                                      */\n/*        /DSHAPELIB_DLLEXPORT                                          */\n/*                                                                      */\n/*      To get both at once it will be necessary to hack this           */\n/*      include file to define:                                         */\n/*                                                                      */\n/*        #define SHPAPI_CALL __declspec(dllexport) __stdcall           */\n/*        #define SHPAPI_CALL1 __declspec(dllexport) * __stdcall        */\n/*                                                                      */\n/*      The complexity of the situtation is partly caused by the        */\n/*      peculiar requirement of Visual C++ that __stdcall appear        */\n/*      after any \"*\"'s in the return value of a function while the     */\n/*      __declspec(dllexport) must appear before them.                  */\n/* -------------------------------------------------------------------- */\n\n#ifdef SHAPELIB_DLLEXPORT\n#  define SHPAPI_CALL __declspec(dllexport)\n#  define SHPAPI_CALL1(x)  __declspec(dllexport) x\n#endif\n\n#ifndef SHPAPI_CALL\n#  define SHPAPI_CALL\n#endif\n\n#ifndef SHPAPI_CALL1\n#  define SHPAPI_CALL1(x)      x SHPAPI_CALL\n#endif\n    \n/************************************************************************/\n/*                             SHP Support.                             */\n/************************************************************************/\ntypedef\tstruct\n{\n    FILE        *fpSHP;\n    FILE\t*fpSHX;\n\n    int\t\tnShapeType;\t\t\t\t/* SHPT_* */\n    \n    int\t\tnFileSize;\t\t\t\t/* SHP file */\n\n    int         nRecords;\n    int\t\tnMaxRecords;\n    int\t\t*panRecOffset;\n    int\t\t*panRecSize;\n\n    double\tadBoundsMin[4];\n    double\tadBoundsMax[4];\n\n    int\t\tbUpdated;\n\n    unsigned char *pabyRec;\n    int         nBufSize;\n} SHPInfo;\n\ntypedef SHPInfo * SHPHandle;\n\n/* -------------------------------------------------------------------- */\n/*      Shape types (nSHPType)                                          */\n/* -------------------------------------------------------------------- */\n#define SHPT_NULL\t0\n#define SHPT_POINT\t1\n#define SHPT_ARC\t3\n#define SHPT_POLYGON\t5\n#define SHPT_MULTIPOINT\t8\n#define SHPT_POINTZ\t11\n#define SHPT_ARCZ\t13\n#define SHPT_POLYGONZ\t15\n#define SHPT_MULTIPOINTZ 18\n#define SHPT_POINTM\t21\n#define SHPT_ARCM\t23\n#define SHPT_POLYGONM\t25\n#define SHPT_MULTIPOINTM 28\n#define SHPT_MULTIPATCH 31\n\n\n/* -------------------------------------------------------------------- */\n/*      Part types - everything but SHPT_MULTIPATCH just uses           */\n/*      SHPP_RING.                                                      */\n/* -------------------------------------------------------------------- */\n\n#define SHPP_TRISTRIP\t0\n#define SHPP_TRIFAN\t1\n#define SHPP_OUTERRING\t2\n#define SHPP_INNERRING\t3\n#define SHPP_FIRSTRING\t4\n#define SHPP_RING\t5\n\n/* -------------------------------------------------------------------- */\n/*      SHPObject - represents on shape (without attributes) read       */\n/*      from the .shp file.                                             */\n/* -------------------------------------------------------------------- */\ntypedef struct\n{\n    int\t\tnSHPType;\n\n    int\t\tnShapeId; /* -1 is unknown/unassigned */\n\n    int\t\tnParts;\n    int\t\t*panPartStart;\n    int\t\t*panPartType;\n    \n    int\t\tnVertices;\n    double\t*padfX;\n    double\t*padfY;\n    double\t*padfZ;\n    double\t*padfM;\n\n    double\tdfXMin;\n    double\tdfYMin;\n    double\tdfZMin;\n    double\tdfMMin;\n\n    double\tdfXMax;\n    double\tdfYMax;\n    double\tdfZMax;\n    double\tdfMMax;\n} SHPObject;\n\n/* -------------------------------------------------------------------- */\n/*      SHP API Prototypes                                              */\n/* -------------------------------------------------------------------- */\nSHPHandle SHPAPI_CALL\n      SHPOpen( const char * pszShapeFile, const char * pszAccess );\nSHPHandle SHPAPI_CALL\n      SHPCreate( const char * pszShapeFile, int nShapeType );\nvoid SHPAPI_CALL\n      SHPGetInfo( SHPHandle hSHP, int * pnEntities, int * pnShapeType,\n                  double * padfMinBound, double * padfMaxBound );\n\nSHPObject SHPAPI_CALL1(*)\n      SHPReadObject( SHPHandle hSHP, int iShape );\nint SHPAPI_CALL\n      SHPWriteObject( SHPHandle hSHP, int iShape, SHPObject * psObject );\n\nvoid SHPAPI_CALL\n      SHPDestroyObject( SHPObject * psObject );\nvoid SHPAPI_CALL\n      SHPComputeExtents( SHPObject * psObject );\nSHPObject SHPAPI_CALL1(*)\n      SHPCreateObject( int nSHPType, int nShapeId,\n                       int nParts, int * panPartStart, int * panPartType,\n                       int nVertices, double * padfX, double * padfY,\n                       double * padfZ, double * padfM );\nSHPObject SHPAPI_CALL1(*)\n      SHPCreateSimpleObject( int nSHPType, int nVertices,\n                             double * padfX, double * padfY, double * padfZ );\n\nint SHPAPI_CALL\n      SHPRewindObject( SHPHandle hSHP, SHPObject * psObject );\n\nvoid SHPAPI_CALL SHPClose( SHPHandle hSHP );\nvoid SHPAPI_CALL SHPWriteHeader( SHPHandle hSHP );\n\nconst char SHPAPI_CALL1(*)\n      SHPTypeName( int nSHPType );\nconst char SHPAPI_CALL1(*)\n      SHPPartTypeName( int nPartType );\n\n/* -------------------------------------------------------------------- */\n/*      Shape quadtree indexing API.                                    */\n/* -------------------------------------------------------------------- */\n\n/* this can be two or four for binary or quad tree */\n#define MAX_SUBNODE\t4\n\ntypedef struct shape_tree_node\n{\n    /* region covered by this node */\n    double\tadfBoundsMin[4];\n    double\tadfBoundsMax[4];\n\n    /* list of shapes stored at this node.  The papsShapeObj pointers\n       or the whole list can be NULL */\n    int\t\tnShapeCount;\n    int\t\t*panShapeIds;\n    SHPObject   **papsShapeObj;\n\n    int\t\tnSubNodes;\n    struct shape_tree_node *apsSubNode[MAX_SUBNODE];\n    \n} SHPTreeNode;\n\ntypedef struct\n{\n    SHPHandle   hSHP;\n    \n    int\t\tnMaxDepth;\n    int\t\tnDimension;\n    \n    SHPTreeNode\t*psRoot;\n} SHPTree;\n\nSHPTree SHPAPI_CALL1(*)\n      SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,\n                     double *padfBoundsMin, double *padfBoundsMax );\nvoid    SHPAPI_CALL\n      SHPDestroyTree( SHPTree * hTree );\n\nint\tSHPAPI_CALL\n      SHPWriteTree( SHPTree *hTree, const char * pszFilename );\nSHPTree SHPAPI_CALL\n      SHPReadTree( const char * pszFilename );\n\nint\tSHPAPI_CALL\n      SHPTreeAddObject( SHPTree * hTree, SHPObject * psObject );\nint\tSHPAPI_CALL\n      SHPTreeAddShapeId( SHPTree * hTree, SHPObject * psObject );\nint\tSHPAPI_CALL\n      SHPTreeRemoveShapeId( SHPTree * hTree, int nShapeId );\n\nvoid \tSHPAPI_CALL\n      SHPTreeTrimExtraNodes( SHPTree * hTree );\n\nint    SHPAPI_CALL1(*)\n      SHPTreeFindLikelyShapes( SHPTree * hTree,\n                               double * padfBoundsMin,\n                               double * padfBoundsMax,\n                               int * );\nint     SHPAPI_CALL\n      SHPCheckBoundsOverlap( double *, double *, double *, double *, int );\n\n/************************************************************************/\n/*                             DBF Support.                             */\n/************************************************************************/\ntypedef\tstruct\n{\n    FILE\t*fp;\n\n    int         nRecords;\n\n    int\t\tnRecordLength;\n    int\t\tnHeaderLength;\n    int\t\tnFields;\n    int\t\t*panFieldOffset;\n    int\t\t*panFieldSize;\n    int\t\t*panFieldDecimals;\n    char\t*pachFieldType;\n\n    char\t*pszHeader;\n\n    int\t\tnCurrentRecord;\n    int\t\tbCurrentRecordModified;\n    char\t*pszCurrentRecord;\n    \n    int\t\tbNoHeader;\n    int\t\tbUpdated;\n} DBFInfo;\n\ntypedef DBFInfo * DBFHandle;\n\ntypedef enum {\n  FTString,\n  FTInteger,\n  FTDouble,\n  FTLogical,\n  FTInvalid,\n  FTDate\n} DBFFieldType;\n\n#define XBASE_FLDHDR_SZ       32\n\nDBFHandle SHPAPI_CALL\n      DBFOpen( const char * pszDBFFile, const char * pszAccess );\nDBFHandle SHPAPI_CALL\n      DBFCreate( const char * pszDBFFile );\n\nint\tSHPAPI_CALL\n      DBFGetFieldCount( DBFHandle psDBF );\nint\tSHPAPI_CALL\n      DBFGetRecordCount( DBFHandle psDBF );\nint\tSHPAPI_CALL\n      DBFAddField( DBFHandle hDBF, const char * pszFieldName,\n                   DBFFieldType eType, int nWidth, int nDecimals );\n\nDBFFieldType SHPAPI_CALL\n      DBFGetFieldInfo( DBFHandle psDBF, int iField, \n                       char * pszFieldName, int * pnWidth, int * pnDecimals );\n\nint SHPAPI_CALL\n      DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName);\n\nint \tSHPAPI_CALL\n      DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField );\ndouble \tSHPAPI_CALL\n      DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );\nconst char SHPAPI_CALL1(*)\n      DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );\nconst char SHPAPI_CALL1(*)\n      DBFReadLogicalAttribute( DBFHandle hDBF, int iShape, int iField );\nint     SHPAPI_CALL\n      DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField );\n\nint SHPAPI_CALL DBFReadSetup(DBFHandle psDBF, int hEntity);\n\nint SHPAPI_CALL DBFReadDeleted(DBFHandle psDBF, int hEntity);\n\nint SHPAPI_CALL\n      DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField, \n                                int nFieldValue );\nint SHPAPI_CALL\n      DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField,\n                               double dFieldValue );\nint SHPAPI_CALL\n      DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField,\n                               const char * pszFieldValue );\nint SHPAPI_CALL\n     DBFWriteNULLAttribute( DBFHandle hDBF, int iShape, int iField );\n\nint SHPAPI_CALL\n     DBFWriteLogicalAttribute( DBFHandle hDBF, int iShape, int iField,\n\t\t\t       const char lFieldValue);\nint SHPAPI_CALL\n     DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,\n                               const void * pValue );\nconst char SHPAPI_CALL1(*)\n      DBFReadTuple(DBFHandle psDBF, int hEntity );\nint SHPAPI_CALL\n      DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple );\n\nDBFHandle SHPAPI_CALL\n      DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename );\n \nvoid\tSHPAPI_CALL\n      DBFClose( DBFHandle hDBF );\nvoid    SHPAPI_CALL\n      DBFUpdateHeader( DBFHandle hDBF );\nchar    SHPAPI_CALL\n      DBFGetNativeFieldType( DBFHandle hDBF, int iField );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ndef _SHAPEFILE_H_INCLUDED */\n"
  },
  {
    "path": "src/shp2sqlite/shp2sqlite.c",
    "content": "/**********************************************************************\n * $Id: shp2pgsql.c 3623 2009-02-03 07:20:16Z pramsey $\n *\n * PostGIS - Spatial Types for PostgreSQL\n * http://postgis.refractions.net\n * Copyright 2001-2003 Refractions Research Inc.\n *\n * This is free software; you can redistribute and/or modify it under\n * the terms of the GNU General Public Licence. See the COPYING file.\n * \n **********************************************************************\n * Using shapelib 1.2.8, this program reads in shape files and \n * processes it's contents into a Insert statements which can be \n * easily piped into a database frontend.\n * Specifically designed to insert type 'geometry' (a custom \n * written PostgreSQL type) for the shape files and PostgreSQL \n * standard types for all attributes of the entity. \n *\n * Original Author: Jeff Lounsbury, jeffloun@refractions.net\n *\n * Maintainer: Sandro Santilli, strk@refractions.net\n *\n **********************************************************************/\n\n#include \"../liblwgeom/postgis_config.h\"\n#include \"shapefil.h\"\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <ctype.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include <errno.h>\n#include \"getopt.h\"\n#ifdef HAVE_ICONV\n#include <iconv.h>\n#endif\n\n#include \"../liblwgeom/liblwgeom.h\"\n\n\n#define\tPOINTTYPE\t1\n#define\tLINETYPE\t2\n#define\tPOLYGONTYPE\t3\n#define\tMULTIPOINTTYPE\t4\n#define\tMULTILINETYPE\t5\n#define\tMULTIPOLYGONTYPE\t6\n#define\tCOLLECTIONTYPE\t7\n\n#define WKBZOFFSET 0x80000000\n#define WKBMOFFSET 0x40000000\n\ntypedef struct {double x, y, z, m;} Point;\n\ntypedef struct Ring {\n\tPoint *list;\t\t/* list of points */\n\tstruct Ring  *next;\n\tint n;\t\t\t/* number of points in list */\n\tunsigned int linked; \t/* number of \"next\" rings */\n} Ring;\n\n/* Values for null_policy global */\nenum {\n\tinsert_null,\n\tskip_null,\n\tabort_on_null\n};\n\n/* globals */\nint\tdump_format = 0; /* 0=insert statements, 1 = dump */\nint\tsqlite_format = 1; /* 0=PostGIS GEOMETRY, 1=SQLite BLOB */\nint     simple_geometries = 0; /* 0 = MULTILINESTRING/MULTIPOLYGON, 1 = LINESTRING/POLYGON */\nint\tquoteidentifiers = 0;\nint\tforceint4 = 0;\nint\tcreateindex = 0;\nint readshape = 1;\nchar    opt = ' ';\nchar    *col_names = NULL;\nchar\t*pgtype;\nint\tistypeM = 0;\nint\tpgdims;\nunsigned int wkbtype;\nchar  \t*shp_file = NULL;\nint\thwgeom = 0; /* old (hwgeom) mode */\n#ifdef HAVE_ICONV\nchar\t*encoding=NULL;\n#endif\nint null_policy = insert_null;\n\nDBFFieldType *types;\t/* Fields type, width and precision */\nSHPHandle  hSHPHandle;\nDBFHandle  hDBFHandle;\nint shpfiletype;\nSHPObject  *obj=NULL;\nint \t*widths;\nint \t*precisions;\nchar    *table=NULL,*schema=NULL,*geom=NULL;\nint     num_fields,num_records,num_entities;\nchar    **field_names;\nint \tsr_id = 0;\n\n/* Prototypes */\nint Insert_attributes(DBFHandle hDBFHandle, int row);\nchar *make_good_string(char *str);\nchar *protect_quotes_string(char *str);\nint PIP( Point P, Point* V, int n );\nvoid *safe_malloc(size_t size);\nvoid CreateTable(void);\nvoid CreateIndex(void);\nvoid usage(char *me, int exitcode, FILE* out);\nvoid InsertPoint(void);\nvoid InsertMultiPoint(void);\nvoid InsertPolygon(void);\nvoid InsertLineString(void);\nvoid OutputGeometry(char *geometry);\nint ParseCmdline(int ARGC, char **ARGV);\nvoid SetPgType(void);\nchar *dump_ring(Ring *ring);\n#ifdef HAVE_ICONV\nchar *utf8(const char *fromcode, char *inputbuf);\n#endif\nint FindPolygons(SHPObject *obj, Ring ***Out);\nvoid ReleasePolygons(Ring **polys, int npolys);\nvoid DropTable(char *schema, char *table, char *geom);\nvoid GetFieldsSpec(void);\nvoid LoadData(void);\nvoid OpenShape(void);\nvoid LowerCase(char *s);\nvoid Cleanup(void);\n\n/*\nstatic char rcsid[] =\n  \"$Id: shp2pgsql.c 3623 2009-02-03 07:20:16Z pramsey $\";\n*/\n\n/* liblwgeom allocator callback - install the defaults (malloc/free/stdout/stderr) */\nvoid lwgeom_init_allocators()\n{\n\tlwgeom_install_default_allocators();\n}\n\n\nvoid *safe_malloc(size_t size)\n{\n\tvoid *ret = malloc(size);\n\tif ( ! ret ) {\n\t\tfprintf(stderr, \"Out of virtual memory\\n\");\n\t\texit(1);\n\t}\n\treturn ret;\n}\n\n#define malloc(x) safe_malloc(x)\n\n\nchar *\nmake_good_string(char *str)\n{\n\t/*\n\t * find all the tabs and make them \\<tab>s\n\t *\n\t * 1. find # of tabs\n\t * 2. make new string \n\t *\n\t * we dont escape already escaped tabs\n\t */\n\n\tchar *result;\n\tchar *ptr, *optr;\n\tint toescape = 0;\n\tsize_t size;\n#ifdef HAVE_ICONV\n\tchar *utf8str=NULL;\n\n\tif ( encoding )\n\t{\n\t\tutf8str=utf8(encoding, str);\n\t\tif ( ! utf8str ) exit(1);\n\t\tstr = utf8str; \n\t}\n#endif\n\n\tptr = str;\n\n\twhile (*ptr) {\n\t\tif ( *ptr == '\\t' || *ptr == '\\\\' ) toescape++;\n\t\tptr++;\n\t}\n\n\tif (toescape == 0) return str;\n\n\tsize = ptr-str+toescape+1;\n\n\tresult = calloc(1, size);\n\n\toptr=result;\n\tptr=str;\n\twhile (*ptr) {\n\t\tif ( *ptr == '\\t' || *ptr == '\\\\' ) *optr++='\\\\';\n\t\t*optr++=*ptr++;\n\t}\n\t*optr='\\0';\n\n#ifdef HAVE_ICONV\n\tif ( encoding ) free(str);\n#endif\n\n\treturn result;\n\t\n}\n\nchar *\nprotect_quotes_string(char *str)\n{\n\t/*\n\t * find all quotes and make them \\quotes\n\t * find all '\\' and make them '\\\\'\n\t * \t \n\t * 1. find # of characters\n\t * 2. make new string \n\t */\n\n\tchar\t*result;\n\tchar\t*ptr, *optr;\n\tint\ttoescape = 0;\n\tsize_t size;\n#ifdef HAVE_ICONV\n\tchar *utf8str=NULL;\n\n\tif ( encoding )\n\t{\n\t\tutf8str=utf8(encoding, str);\n\t\tif ( ! utf8str ) exit(1);\n\t\tstr = utf8str; \n\t}\n#endif\n\n\tptr = str;\n\n\twhile (*ptr) {\n\t\tif ( *ptr == '\\'' || *ptr == '\\\\' ) toescape++;\n\t\tptr++;\n\t}\n\n\tif (toescape == 0) return str;\n\t\n\tsize = ptr-str+toescape+1;\n\n\tresult = calloc(1, size);\n\n\toptr=result;\n\tptr=str;\n\twhile (*ptr) {\n                /* SQLite doesn't support backslash escaping in strings */\n\t\tif ( *ptr == '\\\\' && !sqlite_format ) *optr++='\\\\';\n                if ( *ptr == '\\'') *optr++='\\'';\n\t\t*optr++=*ptr++;\n\t}\n\t*optr='\\0';\n\n#ifdef HAVE_ICONV\n\tif ( encoding ) free(str);\n#endif\n\n\treturn result;\n}\n\n\n/*\n * PIP(): crossing number test for a point in a polygon\n *      input:   P = a point,\n *               V[] = vertex points of a polygon V[n+1] with V[n]=V[0]\n *      returns: 0 = outside, 1 = inside\n */\nint\nPIP( Point P, Point* V, int n )\n{\n\tint cn = 0;    /* the crossing number counter */\n\tint i;\n\n    /* loop through all edges of the polygon */\n    for (i=0; i<n-1; i++) {    /* edge from V[i] to V[i+1] */\n       if (((V[i].y <= P.y) && (V[i+1].y > P.y))    /* an upward crossing */\n        || ((V[i].y > P.y) && (V[i+1].y <= P.y))) { /* a downward crossing */\n            double vt = (float)(P.y - V[i].y) / (V[i+1].y - V[i].y);\n            if (P.x < V[i].x + vt * (V[i+1].x - V[i].x)) /* P.x < intersect */\n                ++cn;   /* a valid crossing of y=P.y right of P.x */\n        }\n    }\n    return (cn&1);    /* 0 if even (out), and 1 if odd (in) */\n\n}\n\n\n/*Insert the attributes from the correct row of dbf file */\n\nint\nInsert_attributes(DBFHandle hDBFHandle, int row)\n{\n   int i,num_fields;\n   char val[1024];\n   char *escval;\n\n   num_fields = DBFGetFieldCount( hDBFHandle );\n   for( i = 0; i < num_fields; i++ )\n   {\n      if(DBFIsAttributeNULL( hDBFHandle, row, i))\n      {\n\n\t\tif(dump_format)\n\t\t{\n\t\t\tprintf(\"\\\\N\");\n\t\t\t//printf(\"\\t\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tprintf(\"NULL\");\n\t\t\t//printf(\",\");\n\t\t}\n\t  }\n\n      else /* Attribute NOT NULL */\n      {\n         switch (types[i]) \n         {\n            case FTInteger:\n            case FTDouble:\n               if ( -1 == snprintf(val, 1024, \"%s\",\n                     DBFReadStringAttribute(hDBFHandle, row, i)) )\n               {\n                  fprintf(stderr, \"Warning: field %d name truncated\\n\", i);\n                  val[1023] = '\\0';\n               }\n\t       /* pg_atoi() does not do this */\n\t       if ( val[0] == '\\0' ) { val[0] = '0'; val[1] = '\\0'; }\n\t       if ( val[strlen(val)-1] == '.' ) val[strlen(val)-1] = '\\0';\n               break;\n\n            case FTString:\n            case FTLogical:\n\t    case FTDate:\n               if ( -1 == snprintf(val, 1024, \"%s\",\n                     DBFReadStringAttribute(hDBFHandle, row, i)) )\n               {\n                  fprintf(stderr, \"Warning: field %d name truncated\\n\", i);\n                  val[1023] = '\\0';\n               }\n               break;\n\n            default:\n               fprintf(stderr,\n                  \"Error: field %d has invalid or unknown field type (%d)\\n\",\n                  i, types[i]);\n               exit(1);\n         }\n \n\t\t\tif (dump_format) {\n\t\t\t\tescval = make_good_string(val);\n\t\t\t\tprintf(\"%s\", escval);\n\t\t\t\t//printf(\"\\t\");\n\t\t\t} else {\n\t\t\t\tescval = protect_quotes_string(val);\n                                if (sqlite_format)\n                                    printf(\"'%s'\", escval);\n                                else\n                                    printf(\"E'%s'\", escval);\n\t\t\t\t//printf(\",\");\n\t\t\t}\n\t\t\tif ( val != escval ) free(escval);\n\t\t }\n\t\t//only put in delimeter if not last field or a shape will follow\n\t\tif(readshape == 1 || i < (num_fields - 1))\n\t\t{\n\t\t\tif (dump_format){\n\t\t\t   printf(\"\\t\");   \n\t\t\t}\n\t\t\telse {\n\t\t\t\tprintf(\",\");   \n\t\t\t}\n\t\t}\n\t}\n\treturn 1;\n}\n\n\n\n\n/*\n * main()     \n * see description at the top of this file\n */\nint\nmain (int ARGC, char **ARGV)\n{\n\n\t/*\n\t * Parse command line\n\t */\n\tif ( ! ParseCmdline(ARGC, ARGV) ) usage(ARGV[0], 2, stderr);\n\n\t/*\n\t * Open shapefile and initialize globals\n\t */\n\tOpenShape();\n\n\tif (readshape == 1){\t\n\t\t/*\n\t\t * Compute output geometry type\n\t\t */\n\t\t \n\t\tSetPgType();\n\t\n                /*\n\t\tfprintf(stderr, \"Shapefile type: %s\\n\", SHPTypeName(shpfiletype));\n\t\tfprintf(stderr, \"Postgis type: %s[%d]\\n\", pgtype, pgdims);\n                */\n\t}\n\n#ifdef HAVE_ICONV\n\tif ( encoding )\n\t{\n\t\tprintf(\"SET CLIENT_ENCODING TO UTF8;\\n\");\n\t}\n#endif /* defined HAVE_ICONV */\n\n\t/*\n\t * Drop table if requested\n\t */\n\tif(opt == 'd') DropTable(schema, table, geom);\n\n\t/*\n\t * Get col names and types for table creation\n\t * and data load.\n\t */\n\tGetFieldsSpec();\n\n\tprintf(\"BEGIN;\\n\");\n\n\t/*\n\t * If not in 'append' mode create the spatial table\n\t */\n\tif(opt != 'a') CreateTable();\n\n\t/*\n\t * Generate INSERT or COPY lines\n\t */\n\tif(opt != 'p') LoadData();\n\n\t/*\n\t * Create GiST index if requested\n\t */\n\tif(createindex) CreateIndex();\n\n\tprintf(\"END;\\n\"); /* End the last transaction */\n\n\n\treturn 0; \n}/*end main() */\n\nvoid\nLowerCase(char *s)\n{\n\tint j;\n\tfor (j=0; j<strlen(s); j++) s[j] = tolower(s[j]);\n}\n\nvoid\nCleanup(void)\n{\n\tif ( col_names ) free(col_names);\n}\n\nvoid\nOpenShape(void)\n{\n\tint j;\n\tSHPObject *obj=NULL;\n\n\tif (readshape == 1)\n\t{\n\t\thSHPHandle = SHPOpen( shp_file, \"rb\" );\n\t\tif (hSHPHandle == NULL) \n\t\t{\n\t\t\tfprintf(stderr, \"%s: shape (.shp) or index files (.shx) can not be opened, will just import attribute data.\\n\", shp_file);\n\t\t\treadshape = 0;\n\t\t}\n\t}\n\t\n\thDBFHandle = DBFOpen( shp_file, \"rb\" );\n\tif ((hSHPHandle == NULL && readshape == 1) || hDBFHandle == NULL){\n\t\tfprintf(stderr, \"%s: dbf file (.dbf) can not be opened.\\n\",shp_file);\n\t\texit(-1);\n\t}\n\t\n\tif (readshape == 1)\n\t{\n\t\tSHPGetInfo(hSHPHandle, &num_entities, &shpfiletype, NULL, NULL);\n\t\n\t\tif ( null_policy == abort_on_null )\n\t\t{\n\t\t\tfor (j=0; j<num_entities; j++)\n\t\t\t{\n\t\t\t\tobj = SHPReadObject(hSHPHandle,j);\n\t\t\t\tif ( ! obj )\n\t\t\t\t{\n\t\t\t\t\tfprintf(stderr, \"Error reading shape object %d\\n\", j);\n\t\t\t\t\texit(1);\n\t\t\t\t}\n\t\t\t\tif ( obj->nVertices == 0 )\n\t\t\t\t{\n\t\t\t\t\tfprintf(stderr, \"Empty geometries found, aborted.\\n\");\n\t\t\t\t\texit(1);\n\t\t\t\t}\n\t\t\t\tSHPDestroyObject(obj);\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tnum_entities = DBFGetRecordCount(hDBFHandle);\n\t}\n\n}\n\nvoid\nCreateTable(void)\n{\n\tint j;\n\tint field_precision, field_width;\n\tDBFFieldType type = -1;\n        const char *pk_type;\n\n\t/* \n\t * Create a table for inserting the shapes into with appropriate\n\t * columns and types\n\t */\n        if (sqlite_format)\n            pk_type = \"integer\";\n        else \n            pk_type = \"serial\";\n\n\tif ( schema )\n\t{\n\t\tprintf(\"CREATE TABLE \\\"%s\\\".\\\"%s\\\" (gid %s PRIMARY KEY\",\n\t\t\tschema, table, pk_type);\n\t}\n\telse\n\t{\n\t\tprintf(\"CREATE TABLE \\\"%s\\\" (gid %s PRIMARY KEY\",\n                        table, pk_type);\n\t}\n\n\tfor(j=0;j<num_fields;j++)\n\t{\n\t\ttype = types[j];\n\t\tfield_width = widths[j];\n\t\tfield_precision = precisions[j];\n\n\t\tprintf(\",\\n\\\"%s\\\" \", field_names[j]);\n\n\t\tif(type == FTString)\n\t\t{\n\t\t\t/* use DBF attribute size as maximum width */\n\t\t\tprintf (\"varchar(%d)\", field_width);\n\t\t}\n\t\telse if (type == FTDate)\n\t\t{\n\t\t\tprintf (\"date\");\n\t\t}\n\t\telse if (type == FTInteger)\n\t\t{\n\t\t\tif ( forceint4 )\n\t\t\t{\n\t\t\t\tprintf (\"int4\");\n\t\t\t}\n\t\t\telse if  ( field_width < 5 )\n\t\t\t{\n\t\t\t\tprintf (\"int2\");\n\t\t\t}\n\t\t\telse if  ( field_width < 10 )\n\t\t\t{\n\t\t\t\tprintf (\"int4\");\n\t\t\t}\n\t\t\telse if  ( field_width < 19 )\n\t\t\t{\n\t\t\t\tprintf (\"int8\");\n\t\t\t}\n\t\t\telse \n\t\t\t{\n\t\t\t\tprintf(\"numeric(%d,0)\",\n\t\t\t\t\tfield_width);\n\t\t\t}\n\t\t}\n\t\telse if(type == FTDouble)\n\t\t{\n\t\t\tif( field_width > 18 )\n\t\t\t{\n\t\t\t\tprintf (\"numeric\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tprintf (\"float8\");\n\t\t\t}\n\t\t}\n\t\telse if(type == FTLogical)\n\t\t{\n\t\t\tprintf (\"boolean\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tprintf (\"Invalid type in DBF file\");\n\t\t}\n\t}\n\tprintf (\");\\n\");\n\n\t/* Create the geometry column with an addgeometry call */\n        if (sqlite_format) {\n            /* SQLite doesn't have a GEOMETRY type */\n            printf(\"ALTER TABLE %s ADD COLUMN %s blob;\", table, geom);\n        } else {\n            if ( schema && readshape == 1 )\n            {\n                    printf(\"SELECT AddGeometryColumn('%s','%s','%s','%d',\",\n                            schema, table, geom, sr_id);\n            }\n            else if (readshape == 1)\n            {\n                    printf(\"SELECT AddGeometryColumn('','%s','%s','%d',\",\n                            table, geom, sr_id);\n            }\n            if (pgtype)\n            { //pgtype will only be set if we are loading geometries\n                    printf(\"'%s',%d);\\n\", pgtype, pgdims);\n            }\n        }\n}\n\nvoid\nCreateIndex(void)\n{\n\t/* \n\t * Create gist index\n\t */\n\tif ( schema )\n\t{\n\t\tprintf(\"CREATE INDEX \\\"%s_%s_gist\\\" ON \\\"%s\\\".\\\"%s\\\" using gist (\\\"%s\\\" gist_geometry_ops);\\n\", table, geom, schema, table, geom);\n\t}\n\telse\n\t{\n\t\tprintf(\"CREATE INDEX \\\"%s_%s_gist\\\" ON \\\"%s\\\" using gist (\\\"%s\\\" gist_geometry_ops);\\n\", table, geom, table, geom);\n\t}\n}\n\nvoid\nLoadData(void)\n{\n\tint j, trans=0;\n\n\tif (dump_format){\n\t\tif ( schema )\n\t\t{\n\t\t\tprintf(\"COPY \\\"%s\\\".\\\"%s\\\" %s FROM stdin;\\n\",\n\t\t\t\tschema, table, col_names);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tprintf(\"COPY \\\"%s\\\" %s FROM stdin;\\n\",\n\t\t\t\ttable, col_names);\n\t\t}\n\t}\n\n\n\t/**************************************************************\n\t * \n\t *   MAIN SHAPE OBJECTS SCAN\n\t * \n\t **************************************************************/\n\tfor (j=0; j<num_entities; j++)\n\t{\n\t\t/*wrap a transaction block around each 250 inserts... */\n\t\tif ( ! dump_format )\n\t\t{\n\t\t\tif (trans == 250) {\n\t\t\t\ttrans=0;\n\t\t\t\tprintf(\"END;\\n\");\n\t\t\t\tprintf(\"BEGIN;\\n\");\n\t\t\t}\n\t\t}\n\t\ttrans++;\n\t\t/* transaction stuff done */\n\n\t\t/* skip the record if it has been deleted */\n\t\tif(readshape != 1 && DBFReadDeleted(hDBFHandle, j)) {\n\t\t\tcontinue; \n\t\t}\n\n\t\t/* open the next object */\n\t\tif (readshape == 1)\n\t\t{\n\t\t\tobj = SHPReadObject(hSHPHandle,j);\n\t\t\tif ( ! obj )\n\t\t\t{\n\t\t\t\tfprintf(stderr, \"Error reading shape object %d\\n\", j);\n\t\t\t\texit(1);\n\t\t\t}\n\t\n\t\t\tif ( null_policy == skip_null && obj->nVertices == 0 )\n\t\t\t{\n\t\t\t\tSHPDestroyObject(obj);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (!dump_format)\n\t\t{\n\t\t\tif ( schema )\n\t\t\t{\n\t\t\t\tprintf(\"INSERT INTO \\\"%s\\\".\\\"%s\\\" %s VALUES (\",\n                                        schema, table, col_names);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t  \t\tprintf(\"INSERT INTO \\\"%s\\\" %s VALUES (\",\n\t\t\t\t\ttable, col_names);\n\t\t\t}\n\t\t}\n\t\tInsert_attributes(hDBFHandle,j);\n\n\t\tif (readshape == 1) \n\t\t{\n\t\t\t/* ---------- NULL SHAPE ----------------- */\n\t\t\tif (obj->nVertices == 0)\n\t\t\t{\n\t\t\t\tif (dump_format) printf(\"\\\\N\\n\");\n\t\t\t\telse printf(\"NULL);\\n\");\n\t\t\t\tSHPDestroyObject(obj);\t\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\tswitch (obj->nSHPType)\n\t\t\t{\n\t\t\t\tcase SHPT_POLYGON:\n\t\t\t\tcase SHPT_POLYGONM:\n\t\t\t\tcase SHPT_POLYGONZ:\n\t\t\t\t\tInsertPolygon();\n\t\t\t\t\tbreak;\n\t\n\t\t\t\tcase SHPT_POINT:\n\t\t\t\tcase SHPT_POINTM:\n\t\t\t\tcase SHPT_POINTZ:\n\t\t\t\tcase SHPT_MULTIPOINT:\n\t\t\t\tcase SHPT_MULTIPOINTM:\n\t\t\t\tcase SHPT_MULTIPOINTZ:\n\t\t\t\t\tInsertPoint();\n\t\t\t\t\tbreak;\n\t\n\t\t\t\tcase SHPT_ARC:\n\t\t\t\tcase SHPT_ARCM:\n\t\t\t\tcase SHPT_ARCZ:\n\t\t\t\t\tInsertLineString();\n\t\t\t\t\tbreak;\n\t\n\t\t\t\tdefault:\n\t\t\t\t\tprintf (\"\\n\\n**** Type is NOT SUPPORTED, type id = %d ****\\n\\n\",\n\t\t\t\t\t\tobj->nSHPType);\n\t\t\t\t\tbreak;\n\t\n\t\t\t}\n\t\t\t\n\t\t\tSHPDestroyObject(obj);\t\n\t\t}\n\t\telse \n\t\t\tif (dump_format){ /*close for dbf only dump format */\n\t\t\t\tprintf(\"\\n\");\n\t\t\t}\n\t\t\telse { /*close for dbf only sql insert format */\n\t\t\t\tprintf(\");\\n\");\n\t\t\t}\n\t\n\t} /* END of MAIN SHAPE OBJECT LOOP */\n\t\n\n\n\tif ((dump_format) ) {\n\t\tprintf(\"\\\\.\\n\");\n\n\t} \n}\n\nvoid\nusage(char *me, int exitcode, FILE* out)\n{\n    /*\n    fprintf(out, \"RCSID: %s RELEASE: %s\\n\", rcsid, POSTGIS_VERSION);\n    */\n\tfprintf(out, \"USAGE: %s [<options>] <shapefile> [<schema>.]<table>\\n\", me);\n\tfprintf(out, \"OPTIONS:\\n\");\n\tfprintf(out, \"  -s <srid>  Set the SRID field. If not specified it defaults to -1.\\n\");\n\tfprintf(out, \"  (-d|a|c|p) These are mutually exclusive options:\\n\");\n\tfprintf(out, \"      -d  Drops the table, then recreates it and populates\\n\");\n\tfprintf(out, \"          it with current shape file data.\\n\");\n\tfprintf(out, \"      -a  Appends shape file into current table, must be\\n\");\n\tfprintf(out, \"          exactly the same table schema.\\n\");\n\tfprintf(out, \"      -c  Creates a new table and populates it, this is the\\n\");\n\tfprintf(out, \"          default if you do not specify any options.\\n\");\n \tfprintf(out, \"      -p  Prepare mode, only creates the table.\\n\");\n\tfprintf(out, \"  -g <geometry_column> Specify the name of the geometry column\\n\");\n\tfprintf(out, \"     (mostly useful in append mode).\\n\");\n\tfprintf(out, \"  -i  Use int4 type for all integer dbf fields.\\n\");\n\tfprintf(out, \"  -S  Generate simple geometries instead of MULTI geometries.\\n\");\n\tfprintf(out, \"  -w  Use wkt format (drops M - drifts coordinates).\\n\");\n#ifdef HAVE_ICONV\n\tfprintf(out, \"  -W <encoding> Specify the character encoding of Shape's\\n\");\n\tfprintf(out, \"     attribute column. (default : \\\"ASCII\\\")\\n\");\n#endif\n\tfprintf(out, \"  -N <policy> Specify NULL geometries handling policy (insert,skip,abort)\\n\");\n\tfprintf(out, \"  -n  Only import DBF file.\\n\");\n    fprintf(out, \"  -? Display this help screen\\n\");\n\texit (exitcode);\n}\n\nvoid\nInsertLineString()\n{\n\tLWCOLLECTION *lwcollection;\n\n\tLWGEOM **lwmultilinestrings;\n\tuchar *serialized_lwgeom;\n\tLWGEOM_UNPARSER_RESULT lwg_unparser_result;\n\n\tDYNPTARRAY **dpas;\n\tPOINT4D point4d;\n\n\tint dims = 0, hasz = 0, hasm = 0;\n\tint result;\n\tint u, v, start_vertex, end_vertex;\n\n\t/* Determine the correct dimensions: note that in hwgeom-compatible mode we cannot use\n\t   the M coordinate */\n\tif (wkbtype & WKBZOFFSET) hasz = 1;\n\tif (!hwgeom)\n\t\tif (wkbtype & WKBMOFFSET) hasm = 1;\n\tTYPE_SETZM(dims, hasz, hasm);\n\n\tif (simple_geometries == 1 && obj->nParts > 1)\n\t{\n\t\tfprintf(stderr, \"We have a Multilinestring with %d parts, can't use -S switch!\\n\", obj->nParts);\n\t\texit(1);\t\n\t}\n\n\t/* Allocate memory for our array of LWLINEs and our dynptarrays */\n\tlwmultilinestrings = malloc(sizeof(LWPOINT *) * obj->nParts);\t\n\tdpas = malloc(sizeof(DYNPTARRAY *) * obj->nParts);\n\n\t/* We need an array of pointers to each of our sub-geometries */\n\tfor (u = 0; u < obj->nParts; u++)\n\t{\n\t\t/* Create a dynptarray containing the line points */\n\t\tdpas[u] = dynptarray_create(obj->nParts, dims);\n\n\t\t/* Set the start/end vertices depending upon whether this is\n\t\ta MULTILINESTRING or not */\n\t\tif ( u == obj->nParts-1 )\n\t\t\tend_vertex = obj->nVertices;\n\t\telse \n\t\t\tend_vertex = obj->panPartStart[u + 1];\n\t\t\n\t\tstart_vertex = obj->panPartStart[u];\n\n\t\tfor (v = start_vertex; v < end_vertex; v++)\n\t\t{\n\t\t\t/* Generate the point */\n\t\t\tpoint4d.x = obj->padfX[v];\n\t\t\tpoint4d.y = obj->padfY[v];\n\t\n\t\t\tif (wkbtype & WKBZOFFSET)\n\t\t\t\tpoint4d.z = obj->padfZ[v];\n\t\t\tif (wkbtype & WKBMOFFSET)\n\t\t\t\tpoint4d.m = obj->padfM[v];\n\t\n\t\t\tdynptarray_addPoint4d(dpas[u], &point4d, 0);\n\t\t}\n\t\n\t\t/* Generate the LWLINE */\n\t\tlwmultilinestrings[u] = lwline_as_lwgeom(lwline_construct(sr_id, NULL, dpas[u]->pa));\n\t}\n\n\t/* If using MULTILINESTRINGs then generate the serialized collection, otherwise just a single LINESTRING */\n\tif (simple_geometries == 0)\n\t{\n\t\tlwcollection = lwcollection_construct(MULTILINETYPE, sr_id, NULL, obj->nParts, lwmultilinestrings);\n\t\tserialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection));\n\t}\n\telse\n\t{\n\t\tserialized_lwgeom = lwgeom_serialize(lwmultilinestrings[0]);\n\t}\n\n\tif (!hwgeom)\n\t\tresult = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL, -1);\n\telse\n\t\tresult = serialized_lwgeom_to_ewkt(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL);\n\t\n\tif (result)\n\t{\n\t\tfprintf(stderr, \"ERROR: %s\\n\", lwg_unparser_result.message);\n\t\texit(1);\t\n\t}\n\n\tOutputGeometry(lwg_unparser_result.wkoutput);\n\n\t/* Free all of the allocated items */\n        lwfree(lwg_unparser_result.wkoutput);\n        lwfree(serialized_lwgeom);\n\n\tfor (u = 0; u < obj->nParts; u++)\n\t{\n        \tlwline_free(lwgeom_as_lwline(lwmultilinestrings[u]));\n        \tlwfree(dpas[u]);\n\t}\n\n\tlwfree(dpas);\n\tlwfree(lwmultilinestrings);\n}\n\nint\nFindPolygons(SHPObject *obj, Ring ***Out)\n{\n\tRing **Outer;    /* Pointers to Outer rings */\n\tint out_index=0; /* Count of Outer rings */\n\tRing **Inner;    /* Pointers to Inner rings */\n\tint in_index=0;  /* Count of Inner rings */\n\tint pi; /* part index */\n\n#if POSTGIS_DEBUG_LEVEL > 0\n\tstatic int call = -1;\n\tcall++;\n#endif\n\n\tLWDEBUGF(4, \"FindPolygons[%d]: allocated space for %d rings\\n\", call, obj->nParts);\n\n\t/* Allocate initial memory */\n\tOuter = (Ring**)malloc(sizeof(Ring*)*obj->nParts);\n\tInner = (Ring**)malloc(sizeof(Ring*)*obj->nParts);\n\n\t/* Iterate over rings dividing in Outers and Inners */\n\tfor (pi=0; pi<obj->nParts; pi++)\n\t{\n\t\tint vi; /* vertex index */\n\t\tint vs; /* start index */\n\t\tint ve; /* end index */\n\t\tint nv; /* number of vertex */\n\t\tdouble area = 0.0;\n\t\tRing *ring;\n\n\t\t/* Set start and end vertexes */\n\t\tif ( pi==obj->nParts-1 ) ve = obj->nVertices;\n\t\telse ve = obj->panPartStart[pi+1];\n\t\tvs = obj->panPartStart[pi];\n\n\t\t/* Compute number of vertexes */\n\t\tnv = ve-vs;\n\n\t\t/* Allocate memory for a ring */\n\t\tring = (Ring*)malloc(sizeof(Ring));\n\t\tring->list = (Point*)malloc(sizeof(Point)*nv);\n\t\tring->n = nv;\n\t\tring->next = NULL;\n\t\tring->linked = 0;\n\n\t\t/* Iterate over ring vertexes */\n\t\tfor ( vi=vs; vi<ve; vi++)\n\t\t{\n\t\t\tint vn = vi+1; /* next vertex for area */\n\t\t\tif ( vn==ve ) vn = vs;\n\n\t\t\tring->list[vi-vs].x = obj->padfX[vi];\n\t\t\tring->list[vi-vs].y = obj->padfY[vi];\n\t\t\tring->list[vi-vs].z = obj->padfZ[vi];\n\t\t\tring->list[vi-vs].m = obj->padfM[vi];\n\n\t\t\tarea += (obj->padfX[vi] * obj->padfY[vn]) -\n\t\t\t\t(obj->padfY[vi] * obj->padfX[vn]); \n\t\t}\n\n\t\t/* Close the ring with first vertex  */\n\t\t/*ring->list[vi].x = obj->padfX[vs]; */\n\t\t/*ring->list[vi].y = obj->padfY[vs]; */\n\t\t/*ring->list[vi].z = obj->padfZ[vs]; */\n\t\t/*ring->list[vi].m = obj->padfM[vs]; */\n\n\t\t/* Clockwise (or single-part). It's an Outer Ring ! */\n\t\tif(area < 0.0 || obj->nParts ==1) {\n\t\t\tOuter[out_index] = ring;\n\t\t\tout_index++;\n\t\t}\n\n\t\t/* Counterclockwise. It's an Inner Ring ! */\n\t\telse {\n\t\t\tInner[in_index] = ring;\n\t\t\tin_index++;\n\t\t}\n\t}\n\n\tLWDEBUGF(4, \"FindPolygons[%d]: found %d Outer, %d Inners\\n\", call, out_index, in_index);\n\n\t/* Put the inner rings into the list of the outer rings */\n\t/* of which they are within */\n\tfor(pi=0; pi<in_index; pi++)\n\t{\n\t\tPoint pt,pt2;\n\t\tint i;\n\t\tRing *inner=Inner[pi], *outer=NULL;\n\n\t\tpt.x = inner->list[0].x;\n\t\tpt.y = inner->list[0].y;\n\n\t\tpt2.x = inner->list[1].x;\n\t\tpt2.y = inner->list[1].y;\n\n\t\tfor(i=0; i<out_index; i++)\n\t\t{\n\t\t\tint in;\n\n\t\t\tin = PIP(pt, Outer[i]->list, Outer[i]->n);\n\t\t\tif( in || PIP(pt2, Outer[i]->list, Outer[i]->n) )\n\t\t\t{\n\t\t\t\touter = Outer[i];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t/*fprintf(stderr, \"!PIP %s\\nOUTE %s\\n\", dump_ring(inner), dump_ring(Outer[i])); */\n\t\t}\n\n\t\tif ( outer )\n\t\t{\n\t\t\touter->linked++;\n\t\t\twhile(outer->next) outer = outer->next;\n\t\t\touter->next = inner;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* The ring wasn't within any outer rings, */\n\t\t\t/* assume it is a new outer ring. */\n\t\t\tLWDEBUGF(4, \"FindPolygons[%d]: hole %d is orphan\\n\", call, pi);\n\n\t\t\tOuter[out_index] = inner;\n\t\t\tout_index++;\n\t\t}\n\t}\n\n\t*Out = Outer;\n\tfree(Inner);\n\n\treturn out_index;\n}\n\nvoid\nReleasePolygons(Ring **polys, int npolys)\n{\n\tint pi;\n\t/* Release all memory */\n\tfor(pi=0; pi<npolys; pi++)\n\t{\n\t\tRing *Poly, *temp;\n\t\tPoly = polys[pi];\n\t\twhile(Poly != NULL){\n\t\t\ttemp = Poly;\n\t\t\tPoly = Poly->next;\n\t\t\tfree(temp->list);\n\t\t\tfree(temp);\n\t\t}\n\t}\n\tfree(polys);\n}\n\n/*This function basically deals with the polygon case. */\n/*it sorts the polys in order of outer,inner,inner, so that inners */\n/*always come after outers they are within  */\nvoid\nInsertPolygon(void)\n{\n\tRing **Outer;\n\tint polygon_total, ring_total;\n\tint pi, vi; // part index and vertex index\n\tint u;\t\n\n\tLWCOLLECTION *lwcollection = NULL;\n\n\tLWGEOM **lwpolygons;\n\tuchar *serialized_lwgeom;\n\tLWGEOM_UNPARSER_RESULT lwg_unparser_result;\n\n\tLWPOLY *lwpoly;\n\tDYNPTARRAY *dpas;\n\tPOINTARRAY ***pas;\n\tPOINT4D point4d;\n\n\tint dims = 0, hasz = 0, hasm = 0;\n\tint result;\n\n\t/* Determine the correct dimensions: note that in hwgeom-compatible mode we cannot use\n\t   the M coordinate */\n\tif (wkbtype & WKBZOFFSET) hasz = 1;\n\tif (!hwgeom)\n\t\tif (wkbtype & WKBMOFFSET) hasm = 1;\n\tTYPE_SETZM(dims, hasz, hasm);\n\n\tpolygon_total = FindPolygons(obj, &Outer);\n\n\tif (simple_geometries == 1 && polygon_total != 1) /* We write Non-MULTI geometries, but have several parts: */\n\t{\n\t\tfprintf(stderr, \"We have a Multipolygon with %d parts, can't use -S switch!\\n\", polygon_total);\n\t\texit(1);\t\t\n\t}\n\n\t/* Allocate memory for our array of LWPOLYs */\n\tlwpolygons = malloc(sizeof(LWPOLY *) * polygon_total);\n\n\t/* Allocate memory for our POINTARRAY pointers for each polygon */\n\tpas = malloc(sizeof(POINTARRAY **) * polygon_total);\n\n\t/* Cycle through each individual polygon */\n\tfor(pi = 0; pi < polygon_total; pi++)\n\t{\n\t\tRing *polyring;\n\t\tint ring_index = 0;\n\n\t\t/* Firstly count through the total number of rings in this polygon */\n\t\tring_total = 0;\n\t\tpolyring = Outer[pi];\n\t\twhile (polyring)\n\t\t{\n\t\t\tring_total++;\n\t\t\tpolyring = polyring->next;\n\t\t}\n\n\t\t/* Reserve memory for the POINTARRAYs representing each ring */\n\t\tpas[pi] = malloc(sizeof(POINTARRAY *) * ring_total);\n\n\t\t/* Cycle through each ring within the polygon, starting with the outer */\n\t\tpolyring = Outer[pi];\n\n\t\twhile (polyring)\n\t\t{\n\t\t\t/* Create a DYNPTARRAY containing the points making up the ring */\n\t\t\tdpas = dynptarray_create(polyring->n, dims);\n\n\t\t\tfor(vi = 0; vi < polyring->n; vi++)\n\t\t\t{\n\t\t\t\t/* Build up a point array of all the points in this ring */\n\t\t\t\tpoint4d.x = polyring->list[vi].x;\n\t\t\t\tpoint4d.y = polyring->list[vi].y;\n\t\t\n\t\t\t\tif (wkbtype & WKBZOFFSET)\n\t\t\t\t\tpoint4d.z = polyring->list[vi].z;\n\t\t\t\tif (wkbtype & WKBMOFFSET)\n\t\t\t\t\tpoint4d.m = polyring->list[vi].m;\n\n\t\t\t\tdynptarray_addPoint4d(dpas, &point4d, 0);\n\t\t\t}\n\n\t\t\t/* Copy the POINTARRAY pointer from the DYNPTARRAY structure so we can\n\t\t\t use the LWPOLY constructor */\n\t\t\tpas[pi][ring_index] = dpas->pa;\n\n\t\t\t/* Free the DYNPTARRAY structure (we don't need this part anymore as we\n\t\t\thave the reference to the internal POINTARRAY) */\n\t\t\tlwfree(dpas);\n\n\t\t\tpolyring = polyring->next;\n\t\t\tring_index++;\n\t\t}\n\n\t\t/* Generate the LWGEOM */\n\t\tlwpoly = lwpoly_construct(sr_id, NULL, ring_total, pas[pi]);\t\n\t\tlwpolygons[pi] = lwpoly_as_lwgeom(lwpoly);\n\t}\n\n\tReleasePolygons(Outer, polygon_total);\n\n\t/* If using MULTIPOLYGONS then generate the serialized collection, otherwise just a single POLYGON */\n\tif (simple_geometries == 0)\n\t{\n\t\tlwcollection = lwcollection_construct(MULTIPOLYGONTYPE, sr_id, NULL, polygon_total, lwpolygons);\n\t\tserialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection));\n\t}\n\telse\n\t{\n\t\tserialized_lwgeom = lwgeom_serialize(lwpolygons[0]);\n\t}\n\n\tif (!hwgeom)\n\t\tresult = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL, -1);\n\telse\n\t\tresult = serialized_lwgeom_to_ewkt(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL);\n\t\n\tif (result)\n\t{\n\t\tfprintf(stderr, \"ERROR: %s\\n\", lwg_unparser_result.message);\n\t\texit(1);\t\n\t}\n\n\tOutputGeometry(lwg_unparser_result.wkoutput);\n\n\t/* Free all of the allocated items */\n        lwfree(lwg_unparser_result.wkoutput);\n        lwfree(serialized_lwgeom);\n\n\t/* Cycle through each polygon, freeing everything we need... */\n\tfor (u = 0; u < polygon_total; u++)\n\t\tlwpoly_free(lwgeom_as_lwpoly(lwpolygons[u]));\n\n\t/* Free the pointer arrays */\n\tlwfree(pas);\n\tlwfree(lwpolygons);\n\tif (simple_geometries == 0)\n\t\tlwfree(lwcollection);\n}\n\n/*\n * Insert either a POINT or MULTIPOINT into the output stream\n */\nvoid\nInsertPoint(void)\n{\n\tLWCOLLECTION *lwcollection;\n\n\tLWGEOM **lwmultipoints;\n\tuchar *serialized_lwgeom;\n\tLWGEOM_UNPARSER_RESULT lwg_unparser_result;\n\n\tDYNPTARRAY **dpas;\n\tPOINT4D point4d;\n\n\tint dims = 0, hasz = 0, hasm = 0;\n\tint result;\n\tint u;\n\n\t/* Determine the correct dimensions: note that in hwgeom-compatible mode we cannot use\n\t   the M coordinate */\n\tif (wkbtype & WKBZOFFSET) hasz = 1;\n\tif (!hwgeom)\n\t\tif (wkbtype & WKBMOFFSET) hasm = 1;\n\tTYPE_SETZM(dims, hasz, hasm);\n\n\t/* Allocate memory for our array of LWPOINTs and our dynptarrays */\n\tlwmultipoints = malloc(sizeof(LWPOINT *) * obj->nVertices);\t\n\tdpas = malloc(sizeof(DYNPTARRAY *) * obj->nVertices);\n\n\t/* We need an array of pointers to each of our sub-geometries */\n\tfor (u = 0; u < obj->nVertices; u++)\n\t{\n\t\t/* Generate the point */\n\t\tpoint4d.x = obj->padfX[u];\n\t\tpoint4d.y = obj->padfY[u];\n\n\t\tif (wkbtype & WKBZOFFSET)\n\t\t\tpoint4d.z = obj->padfZ[u];\n\t\tif (wkbtype & WKBMOFFSET)\n\t\t\tpoint4d.m = obj->padfM[u];\n\n\t\t/* Create a dynptarray containing a single point */\n\t\tdpas[u] = dynptarray_create(1, dims);\n\t\tdynptarray_addPoint4d(dpas[u], &point4d, 0);\n\n\t\t/* Generate the LWPOINT */\n\t\tlwmultipoints[u] = lwpoint_as_lwgeom(lwpoint_construct(sr_id, NULL, dpas[u]->pa));\n\t}\n\n\t/* If we have more than 1 vertex then we are working on a MULTIPOINT and so generate a MULTIPOINT\n\trather than a POINT */\n\tif (obj->nVertices > 1)\n\t{\n\t\tlwcollection = lwcollection_construct(MULTIPOINTTYPE, sr_id, NULL, obj->nVertices, lwmultipoints);\n\t\tserialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection));\n\t}\n\telse\n\t{\n\t\tserialized_lwgeom = lwgeom_serialize(lwmultipoints[0]);\n\t}\n\n\tif (!hwgeom)\n\t\tresult = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL, -1);\n\telse\n\t\tresult = serialized_lwgeom_to_ewkt(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL);\n\t\n\tif (result)\n\t{\n\t\tfprintf(stderr, \"ERROR: %s\\n\", lwg_unparser_result.message);\n\t\texit(1);\t\n\t}\n\n\tOutputGeometry(lwg_unparser_result.wkoutput);\n\n\t/* Free all of the allocated items */\n        lwfree(lwg_unparser_result.wkoutput);\n        lwfree(serialized_lwgeom);\n\n\tfor (u = 0; u < obj->nVertices; u++)\n\t{\n        \tlwpoint_free(lwgeom_as_lwpoint(lwmultipoints[u]));\n        \tlwfree(dpas[u]);\n\t}\n\n\tlwfree(dpas);\n\tlwfree(lwmultipoints);\n}\n\nvoid\nOutputGeometry(char *geometry)\n{\n\t/* This function outputs the specified geometry string (WKB or WKT) formatted\n\t * according to whether we have specified dump format or hwgeom format */\n\n\tif (hwgeom) \n\t{\n\t\tif (!dump_format)\n\t\t\tprintf(\"GeomFromText('\"); \n\t\telse\n\t\t{\n\t\t\t/* Output SRID if relevant */\n\t\t\tif (sr_id != 0)\n\t\t\t\tprintf(\"SRID=%d;\", sr_id);\n\t\t}\n\n\t\tprintf(\"%s\", geometry);\n\n\t\tif (!dump_format)\n\t\t{\n\t\t\tprintf(\"'\");\n\n\t\t\t/* Output SRID if relevant */\n\t\t\tif (sr_id != 0)\n\t\t\t\tprintf(\", %d)\", sr_id);\n\n\t\t\tprintf(\");\\n\");\n\t\t}\n\t\telse\n\t\t\tprintf(\"\\n\");\n\t}\t\n\telse\n\t{\n\t\tif (!dump_format) {\n                    if (sqlite_format)\n                        /* SQLite BLOBs are formatted as a string of hex\n                         * digits with an X before the leading quote. */\n\t\t\tprintf(\"X'\");\n                    else\n\t\t\tprintf(\"'\");\n                }\n\n\t\tprintf(\"%s\", geometry);\n\n\t\tif (!dump_format)\n\t\t\tprintf(\"');\\n\");\n\t\telse\n\t\t\tprintf(\"\\n\");\n\t}\n}\n\n\nint\nParseCmdline(int ARGC, char **ARGV)\n{\n\tint c;\n\tint curindex=0;\n\tchar  *ptr;\n\textern char *optarg;\n\textern int optind;\n\n\tif ( ARGC == 1 ) {\n\t\tusage(ARGV[0], 0, stdout);\n\t}\n\n\twhile ((c = pgis_getopt(ARGC, ARGV, \"kcdapDLs:Sg:iW:wIN:n\")) != EOF){\n\t\tswitch (c) {\n\t\t\tcase 'c':\n\t\t\t\tif (opt == ' ')\n\t\t\t\t\t opt ='c';\n\t\t\t\telse\n\t\t\t\t\t return 0;\n\t\t\t\tbreak;\n\t\t\tcase 'd':\n\t\t\t\tif (opt == ' ')\n\t\t\t\t\t opt ='d';\n\t\t\t\telse\n\t\t\t\t\t return 0;\n\t\t\t\tbreak;\n\t\t\tcase 'a':\n\t\t\t\tif (opt == ' ')\n\t\t\t\t\t opt ='a';\n\t\t\t\telse\n\t\t\t\t\t return 0;\n\t\t\t\tbreak;\n\t\t\tcase 'p':\n\t\t\t\tif (opt == ' ')\n\t\t\t\t\t opt ='p';\n\t\t\t\telse\n\t\t\t\t\t return 0;\n\t\t\t\tbreak;\n\t\t\tcase 'D':\n\t\t\t\tdump_format =1;\n\t\t\t\tbreak;\n                        case 'L':\n                                sqlite_format=1;\n                                break;\n\t\t\tcase 'S':\n\t\t\t\tsimple_geometries =1;\n\t\t\t\tbreak;\n\t\t\tcase 's':\n\t\t\t\t(void)sscanf(optarg, \"%d\", &sr_id);\n\t\t\t\tbreak;\n\t\t\tcase 'g':\n\t\t\t\tgeom = optarg;\n\t\t\t\tbreak;\n\t\t\tcase 'k':\n\t\t\t\tquoteidentifiers = 1;\n\t\t\t\tbreak;\n\t\t\tcase 'i':\n\t\t\t\tforceint4 = 1;\n\t\t\t\tbreak;\n\t\t\tcase 'I':\n\t\t\t\tcreateindex = 1;\n\t\t\t\tbreak;\n\t\t\tcase 'w':\n\t\t\t\thwgeom = 1;\n\t\t\t\tbreak;\n\t\t\tcase 'n':\n\t\t\t\treadshape = 0;\n\t\t\t\tbreak;\n\t\t\tcase 'W':\n#ifdef HAVE_ICONV\n\t\t\t\tencoding = optarg;\n#else\n\t\t\t\tfprintf(stderr, \"WARNING: the -W switch will have no effect. UTF8 disabled at compile time\\n\");\n#endif\n\t\t\t\tbreak;\n\t\t\tcase 'N':\n\t\t\t\tswitch (optarg[0])\n\t\t\t\t{\t\n\t\t\t\t\tcase 'a':\n\t\t\t\t\t\tnull_policy = abort_on_null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'i':\n\t\t\t\t\t\tnull_policy = insert_null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 's':\n\t\t\t\t\t\tnull_policy = skip_null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tfprintf(stderr, \"Unsupported NULL geometry handling policy.\\nValid policies: insert, skip, abort\\n\");\n\t\t\t\t\t\texit(1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '?':\n\t\t\t\tusage(ARGV[0], 0, stdout); \n\t\t\tdefault:              \n\t\t\t\treturn 0;\n\t\t}\n\t}\n\n\tif ( !sr_id ) sr_id = -1;\n\n\tif ( !geom ) geom = \"the_geom\";\n\n\tif ( opt==' ' ) opt = 'c';\n\n\tfor (; optind < ARGC; optind++){\n\t\tif(curindex ==0){\n\t\t\tshp_file = ARGV[optind];\n\t\t}else if(curindex == 1){\n\t\t\ttable = ARGV[optind];\n\t\t\tif ( (ptr=strchr(table, '.')) )\n\t\t\t{\n\t\t\t\t*ptr = '\\0';\n\t\t\t\tschema = table;\n\t\t\t\ttable = ptr+1;\n\t\t\t}\n\t\t}\n\t\tcurindex++;\n\t}\n\t\n\t/*\n\t * Third argument (if present) is supported for compatibility\n\t * with old shp2pgsql versions taking also database name.\n\t */\n\tif(curindex < 2 || curindex > 3){\n\t\treturn 0;\n\t}\n\n\t/* \n\t * Transform table name to lower case unless asked\n\t * to keep original case (we'll quote it later on)\n\t */\n\tif ( ! quoteidentifiers )\n\t{\n\t\tLowerCase(table);\n\t\tif ( schema ) LowerCase(schema);\n\t}\n\n\treturn 1;\n}\n\n\nvoid\nSetPgType(void)\n{\n\tswitch(shpfiletype)\n\t{\n\t\tcase SHPT_POINT: /* Point */\n\t\t\tpgtype = \"POINT\";\n\t\t\twkbtype = POINTTYPE;\n\t\t\tpgdims = 2;\n\t\t\tbreak;\n\t\tcase SHPT_ARC: /* PolyLine */\n\t\t\tpgtype = \"MULTILINESTRING\";\n\t\t\twkbtype = MULTILINETYPE ;\n\t\t\tpgdims = 2;\n\t\t\tbreak;\n\t\tcase SHPT_POLYGON: /* Polygon */\n\t\t\tpgtype = \"MULTIPOLYGON\";\n\t\t\twkbtype = MULTIPOLYGONTYPE;\n\t\t\tpgdims = 2;\n\t\t\tbreak;\n\t\tcase SHPT_MULTIPOINT: /* MultiPoint */\n\t\t\tpgtype = \"MULTIPOINT\";\n\t\t\twkbtype = MULTIPOINTTYPE;\n\t\t\tpgdims = 2;\n\t\t\tbreak;\n\t\tcase SHPT_POINTM: /* PointM */\n\t\t\twkbtype = POINTTYPE | WKBMOFFSET;\n\t\t\tif ( ! hwgeom ) {\n\t\t\t\tpgtype = \"POINTM\";\n\t\t\t\tpgdims = 3;\n\t\t\t\tistypeM = 1;\n\t\t\t} else {\n\t\t\t\tpgtype = \"POINT\";\n\t\t\t\tpgdims = 2;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SHPT_ARCM: /* PolyLineM */\n\t\t\twkbtype = MULTILINETYPE | WKBMOFFSET;\n\t\t\tif ( ! hwgeom ) {\n\t\t\t\tpgtype = \"MULTILINESTRINGM\";\n\t\t\t\tpgdims = 3;\n\t\t\t\tistypeM = 1;\n\t\t\t} else {\n\t\t\t\tpgtype = \"MULTILINESTRING\";\n\t\t\t\tpgdims = 2;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SHPT_POLYGONM: /* PolygonM */\n\t\t\twkbtype = MULTIPOLYGONTYPE | WKBMOFFSET;\n\t\t\tif ( ! hwgeom ) {\n\t\t\t\tpgtype = \"MULTIPOLYGONM\";\n\t\t\t\tpgdims = 3;\n\t\t\t\tistypeM = 1;\n\t\t\t} else {\n\t\t\t\tpgtype = \"MULTIPOLYGON\";\n\t\t\t\tpgdims = 2;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SHPT_MULTIPOINTM: /* MultiPointM */\n\t\t\twkbtype = MULTIPOINTTYPE | WKBMOFFSET;\n\t\t\tif ( ! hwgeom ) {\n\t\t\t\tpgtype = \"MULTIPOINTM\";\n\t\t\t\tpgdims = 3;\n\t\t\t\tistypeM = 1;\n\t\t\t} else {\n\t\t\t\tpgtype = \"MULTIPOINT\";\n\t\t\t\tpgdims = 2;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SHPT_POINTZ: /* PointZ */\n\t\t\twkbtype = POINTTYPE | WKBMOFFSET | WKBZOFFSET;\n\t\t\tpgtype = \"POINT\";\n\t\t\tif ( ! hwgeom ) pgdims = 4;\n\t\t\telse pgdims = 3;\n\t\t\tbreak;\n\t\tcase SHPT_ARCZ: /* PolyLineZ */\n\t\t\tpgtype = \"MULTILINESTRING\";\n\t\t\twkbtype = MULTILINETYPE | WKBZOFFSET | WKBMOFFSET;\n\t\t\tif ( ! hwgeom ) pgdims = 4;\n\t\t\telse pgdims = 3;\n\t\t\tbreak;\n\t\tcase SHPT_POLYGONZ: /* MultiPolygonZ */\n\t\t\tpgtype = \"MULTIPOLYGON\";\n\t\t\twkbtype = MULTIPOLYGONTYPE | WKBZOFFSET | WKBMOFFSET;\n\t\t\tif ( ! hwgeom ) pgdims = 4;\n\t\t\telse pgdims = 3;\n\t\t\tbreak;\n\t\tcase SHPT_MULTIPOINTZ: /* MultiPointZ */\n\t\t\tpgtype = \"MULTIPOINT\";\n\t\t\twkbtype = MULTIPOINTTYPE | WKBZOFFSET | WKBMOFFSET;\n\t\t\tif ( ! hwgeom ) pgdims = 4;\n\t\t\telse pgdims = 3;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tpgtype = \"GEOMETRY\";\n\t\t\twkbtype = COLLECTIONTYPE | WKBZOFFSET | WKBMOFFSET;\n\t\t\tpgdims = 4;\n\t\t\tfprintf(stderr, \"Unknown geometry type: %d\\n\",\n\t\t\t\tshpfiletype);\n\t\t\tbreak;\n\t}\n\n        if (simple_geometries)\n        {\n                // adjust geometry name for CREATE TABLE by skipping MULTI\n                if ((wkbtype & 0x7) == MULTIPOLYGONTYPE) pgtype += 5;\n                if ((wkbtype & 0x7) == MULTILINETYPE) pgtype += 5;\n        }                        \n}\n\nchar *\ndump_ring(Ring *ring)\n{\n\tchar *buf = malloc(256*ring->n);\n\tint i;\n\n\tbuf[0] = '\\0';\n\tfor (i=0; i<ring->n; i++)\n\t{\n\t\tif (i) strcat(buf, \",\");\n\t\tsprintf(buf+strlen(buf), \"%g %g\",\n\t\t\tring->list[i].x,\n\t\t\tring->list[i].y);\n\t}\n\treturn buf;\n}\n\nvoid\nDropTable(char *schema, char *table, char *geom)\n{\n\t\t/*---------------Drop the table--------------------------\n\t\t * TODO: if the table has more then one geometry column\n\t\t * the DROP TABLE call will leave spurious records in\n\t\t * geometry_columns. \n\t\t *\n\t\t * If the geometry column in the table being dropped\n\t\t * does not match 'the_geom' or the name specified with\n\t\t * -g an error is returned by DropGeometryColumn. \n\t\t *\n\t\t * The table to be dropped might not exist.\n\t\t *\n\t\t */\n\t\tif ( schema )\n\t\t{\n\t\t\tif (readshape == 1){\n\t\t\t\tprintf(\"SELECT DropGeometryColumn('%s','%s','%s');\\n\",\n\t\t\t\t\tschema, table, geom);\n\t\t\t}\n\t\t\tprintf(\"DROP TABLE \\\"%s\\\".\\\"%s\\\";\\n\", schema, table);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (readshape == 1){\n\t\t\t\tprintf(\"SELECT DropGeometryColumn('','%s','%s');\\n\",\n\t\t\t\t\ttable, geom);\n\t\t\t}\n\t\t\tprintf(\"DROP TABLE \\\"%s\\\";\\n\", table);\n\t\t}\n}\n\nvoid\nGetFieldsSpec(void)\n{\n/*\n * Shapefile (dbf) field name are at most 10chars + 1 NULL.\n * Postgresql field names are at most 63 bytes + 1 NULL.\n */\n#define MAXFIELDNAMELEN 64\n\tint field_precision, field_width;\n\tint j, z;\n\tchar  name[MAXFIELDNAMELEN];\n\tchar  name2[MAXFIELDNAMELEN];\n\tDBFFieldType type = -1;\n#ifdef HAVE_ICONV\n\tchar *utf8str;\n#endif\n\n\tnum_fields = DBFGetFieldCount( hDBFHandle );\n\tnum_records = DBFGetRecordCount(hDBFHandle);\n\tfield_names = malloc(num_fields*sizeof(char*));\n\ttypes = (DBFFieldType *)malloc(num_fields*sizeof(int));\n\twidths = malloc(num_fields*sizeof(int));\n\tprecisions = malloc(num_fields*sizeof(int));\n\tif (readshape == 1)\n\t{\n\t\tcol_names = malloc((num_fields+2) * sizeof(char) * MAXFIELDNAMELEN);\n\t}\n\t{\t//for dbf only, we do not need to allocate slot for the_geom\n\t\tcol_names = malloc((num_fields+1) * sizeof(char) * MAXFIELDNAMELEN);\n\t}\n\tstrcpy(col_names, \"(\" );\n\n\t/*fprintf(stderr, \"Number of fields from DBF: %d\\n\", num_fields); */\n\tfor(j=0;j<num_fields;j++)\n\t{\n\t\ttype = DBFGetFieldInfo(hDBFHandle, j, name, &field_width, &field_precision); \n\n/*fprintf(stderr, \"Field %d (%s) width/decimals: %d/%d\\n\", j, name, field_width, field_precision); */\n\t\ttypes[j] = type;\n\t\twidths[j] = field_width;\n\t\tprecisions[j] = field_precision;\n\n#ifdef HAVE_ICONV\n\t\tif ( encoding )\n\t\t{\n\t\t\tutf8str = utf8(encoding, name);\n\t\t\tif ( ! utf8str ) exit(1);\n\t\t\tstrcpy(name, utf8str);\n\t\t\tfree(utf8str);\n\t\t}\n#endif\n\n\n\t\t/*\n\t\t * Make field names lowercase unless asked to\n\t\t * keep identifiers case.\n\t\t */\n\t\tif ( ! quoteidentifiers ) LowerCase(name);\n\n\t\t/*\n\t\t * Escape names starting with the\n\t\t * escape char (_), those named 'gid'\n\t\t * or after pgsql reserved attribute names\n\t\t */\n\t\tif( name[0]=='_' ||\n\t\t\t! strcmp(name,\"gid\") ||\n\t\t\t! strcmp(name, \"tableoid\") ||\n\t\t\t! strcmp(name, \"cmax\") ||\n\t\t\t! strcmp(name, \"xmax\") ||\n\t\t\t! strcmp(name, \"cmin\") ||\n\t\t\t! strcmp(name, \"primary\") ||\n\t\t\t! strcmp(name, \"oid\") ||\n\t\t\t! strcmp(name, \"ctid\") )\n\t\t{\n\t\t\tstrcpy(name2+2, name);\n\t\t\tname2[0] = '_';\n\t\t\tname2[1] = '_';\n\t\t\tstrcpy(name, name2);\n\t\t}\n\n\t\t/* Avoid duplicating field names */\n\t\tfor(z=0; z < j ; z++){\n\t\t\tif(strcmp(field_names[z],name)==0){\n\t\t\t\tstrcat(name,\"__\");\n\t\t\t\tsprintf(name+strlen(name),\"%i\",j);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\t\n\n\t\tfield_names[j] = malloc (strlen(name)+1);\n\t\tstrcpy(field_names[j], name);\n\n\t\t/*sprintf(col_names, \"%s\\\"%s\\\",\", col_names, name);*/\n\t\tstrcat(col_names, \"\\\"\");\n\t\tstrcat(col_names, name);\n\t\tif (readshape == 1 || j < (num_fields - 1)){\n\t\t\t//don't include last comma if its the last field and no geometry field will follow\n\t\t\tstrcat(col_names, \"\\\",\");\n\t\t}\n\t\telse {\n\t\t\tstrcat(col_names, \"\\\"\");\n\t\t}\n\t}\n\t/*sprintf(col_names, \"%s\\\"%s\\\")\", col_names, geom);*/\n\tif (readshape == 1){\n\t\tstrcat(col_names, geom);\n\t}\n\tstrcat(col_names, \")\");\n}\n\n#ifdef HAVE_ICONV\n\nchar *\nutf8 (const char *fromcode, char *inputbuf)\n{\n\ticonv_t cd;\n\tchar *outputptr;\n\tchar *outputbuf;\n\tsize_t outbytesleft;\n\tsize_t inbytesleft;\n\n\tinbytesleft = strlen (inputbuf);\n\n\tcd = iconv_open (\"UTF-8\", fromcode);\n\tif (cd == (iconv_t) - 1)\n\t{\n\t\tfprintf(stderr, \"utf8: iconv_open: %s\\n\", strerror (errno));\n\t\treturn NULL;\n\t}\n\n\toutbytesleft = inbytesleft*3+1; /* UTF8 string can be 3 times larger */\n\t\t\t\t\t/* then local string */\n\toutputbuf = (char *) malloc (outbytesleft);\n\tif (!outputbuf)\n\t{\n\t\tfprintf(stderr, \"utf8: malloc: %s\\n\", strerror (errno));\n\t\treturn NULL;\n\t}\n\tmemset (outputbuf, 0, outbytesleft);\n\toutputptr = outputbuf;\n\n\tif (-1==iconv(cd, &inputbuf, &inbytesleft, &outputptr, &outbytesleft))\n\t{\n\t\tfprintf(stderr, \"utf8: %s\", strerror (errno));\n\t\treturn NULL;\n\t}\n\n\ticonv_close (cd);\n\n\treturn outputbuf;\n}\n\n#endif /* defined HAVE_ICONV */\n\n/**********************************************************************\n * $Log$\n * Revision 1.109  2008/04/09 14:12:17  robe\n *         - Added support to load dbf-only files\n * \n * Revision 1.108  2006/06/16 14:12:17  strk\n *         - BUGFIX in pgsql2shp successful return code.\n *         - BUGFIX in shp2pgsql handling of MultiLine WKT.\n *\n * Revision 1.107  2006/04/18 09:16:26  strk\n * Substituted bzero() use with memset()\n *\n * Revision 1.106  2006/01/16 10:42:58  strk\n * Added support for Bool and Date DBF<=>PGIS mapping\n *\n * Revision 1.105  2006/01/09 16:40:16  strk\n * ISO C90 comments, signedness mismatch fixes\n *\n * Revision 1.104  2005/11/01 09:25:47  strk\n * Reworked NULL geometries handling code letting user specify policy (insert,skip,abort). Insert is the default.\n *\n * Revision 1.103  2005/10/24 15:54:22  strk\n * fixed wrong assumption about maximum size of integer attributes (width is maximum size of text representation)\n *\n * Revision 1.102  2005/10/24 11:30:59  strk\n *\n * Fixed a bug in string attributes handling truncating values of maximum\n * allowed length, curtesy of Lars Roessiger.\n * Reworked integer attributes handling to be stricter in dbf->sql mapping\n * and to allow for big int8 values in sql->dbf conversion\n *\n * Revision 1.101  2005/10/21 11:33:55  strk\n * Applied patch by Lars Roessiger handling numerical values with a trailing decima\n * l dot\n *\n * Revision 1.100  2005/10/13 13:40:20  strk\n * Fixed return code from shp2pgsql\n *\n * Revision 1.99  2005/10/03 18:08:55  strk\n * Stricter string attributes lenght handling. DBF header will be used\n * to set varchar maxlenght, (var)char typmod will be used to set DBF header\n * len.\n *\n * Revision 1.98  2005/10/03 07:45:58  strk\n * Issued a warning when -W is specified and no UTF8 support has been compiled in.\n *\n * Revision 1.97  2005/09/30 08:59:29  strk\n * 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\n *\n * Revision 1.96  2005/08/29 22:36:25  strk\n * Removed premature object destruction in InsertLineString{WKT,} causing segfault\n *\n * Revision 1.95  2005/08/29 11:48:33  strk\n * Fixed sprintf() calls to avoid overlapping memory,\n * reworked not-null objects existance check to reduce startup costs.\n *\n * Revision 1.94  2005/07/27 02:47:14  strk\n * Support for multibyte field names in loader\n *\n * Revision 1.93  2005/07/27 02:35:50  strk\n * Minor cleanups in loader\n *\n * Revision 1.92  2005/07/27 02:07:01  strk\n * Fixed handling of POINT types as WKT (-w) in loader\n *\n * Revision 1.91  2005/07/04 09:47:03  strk\n * Added conservative iconv detection code\n *\n * Revision 1.90  2005/06/16 17:55:58  strk\n * Added -I switch for GiST index creation in loader\n *\n * Revision 1.89  2005/04/21 09:08:34  strk\n * Applied patch from Ron Mayer fixing a segfault in string escaper funx\n *\n * Revision 1.88  2005/04/14 12:58:59  strk\n * Applied patch by Gino Lucrezi fixing bug in string escaping code.\n *\n * Revision 1.87  2005/04/06 14:16:43  strk\n * Removed manual update of gid field.\n *\n * Revision 1.86  2005/04/06 14:02:08  mschaber\n * added -p option (prepare mode) that spits out the table schema without\n * inserting any data.\n *\n * Revision 1.85  2005/04/06 10:46:10  strk\n * Bugfix in -w (hwgeom) handling of ZM shapefiles.\n * Big reorganizzation of code to easy maintainance.\n *\n * Revision 1.84  2005/04/04 20:51:26  strk\n * Added -w flag to output old (WKT/HWGEOM) sql.\n *\n * Revision 1.83  2005/03/15 12:24:40  strk\n * hole-in-ring detector made more readable\n *\n * Revision 1.82  2005/03/14 22:02:31  strk\n * Fixed holes handling.\n *\n * Revision 1.81  2005/03/08 11:06:33  strk\n * modernized old-style parameter declarations\n *\n * Revision 1.80  2005/03/04 14:48:22  strk\n * Applied patch from Jonne Savolainen fixing multilines handling\n *\n * Revision 1.79  2005/01/31 22:15:22  strk\n * Added maintainer notice, to reduce Jeff-strk mail bounces\n *\n * Revision 1.78  2005/01/17 09:21:13  strk\n * Added one more bytes for terminating NULL in utf8 encoder\n *\n * Revision 1.77  2005/01/16 16:50:01  strk\n * String escaping algorithm made simpler and more robust.\n * Removed escaped strings leaking.\n * Fixed UTF8 encoder to allocate enough space for 3bytes chars strings.\n *\n * Revision 1.76  2005/01/12 17:03:20  strk\n * Added optional UTF8 output support as suggested by IIDA Tetsushi\n *\n * Revision 1.75  2004/11/15 10:51:35  strk\n * Fixed a bug in PIP invocation, added some debugging lines.\n *\n * Revision 1.74  2004/10/17 13:25:44  strk\n * removed USE_WKB partially-used define\n *\n * Revision 1.73  2004/10/17 13:24:44  strk\n * HEXWKB polygon\n *\n * Revision 1.72  2004/10/17 12:59:12  strk\n * HEXWKB multiline output\n *\n * Revision 1.71  2004/10/17 12:26:02  strk\n * Point and MultiPoint loaded using HEXWKB.\n *\n * Revision 1.70  2004/10/15 22:01:35  strk\n * Initial WKB functionalities\n *\n * Revision 1.69  2004/10/07 21:52:28  strk\n * Lots of rewriting/cleanup. TypeM/TypeZ supports.\n *\n * Revision 1.68  2004/10/07 06:54:24  strk\n * cleanups\n *\n * Revision 1.67  2004/10/06 10:11:16  strk\n * Other separator fixes\n *\n * Revision 1.66  2004/10/06 09:40:27  strk\n * Handled 0-DBF-attributes corner case.\n *\n * Revision 1.65  2004/09/20 17:13:31  strk\n * changed comments to better show shape type handling\n *\n * Revision 1.64  2004/08/20 08:14:37  strk\n * Whole output wrapped in transaction blocks.\n * Drops are out of transaction, and multiple transactions are used\n * for INSERT mode.\n *\n **********************************************************************/\n"
  },
  {
    "path": "src/shp2sqlite/shpopen.c",
    "content": "/******************************************************************************\n * $Id: shpopen.c 2785 2008-05-27 15:08:20Z mcayland $\n *\n * Project:  Shapelib\n * Purpose:  Implementation of core Shapefile read/write functions.\n * Author:   Frank Warmerdam, warmerdam@pobox.com\n *\n ******************************************************************************\n * Copyright (c) 1999, 2001, Frank Warmerdam\n *\n * This software is available under the following \"MIT Style\" license,\n * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This\n * option is discussed in more detail in shapelib.html.\n *\n * --\n * \n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included\n * in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n * DEALINGS IN THE SOFTWARE.\n ******************************************************************************\n *\n * $Log$\n * Revision 1.5  2003/12/01 20:52:00  strk\n * shapelib put in sync with gdal cvs\n *\n * Revision 1.43  2003/12/01 16:20:08  warmerda\n * be careful of zero vertex shapes\n *\n * Revision 1.42  2003/12/01 14:58:27  warmerda\n * added degenerate object check in SHPRewindObject()\n *\n * Revision 1.41  2003/07/08 15:22:43  warmerda\n * avoid warning\n *\n * Revision 1.40  2003/04/21 18:30:37  warmerda\n * added header write/update public methods\n *\n * Revision 1.39  2002/08/26 06:46:56  warmerda\n * avoid c++ comments\n *\n * Revision 1.38  2002/05/07 16:43:39  warmerda\n * Removed debugging printf.\n *\n * Revision 1.37  2002/04/10 17:35:22  warmerda\n * fixed bug in ring reversal code\n *\n * Revision 1.36  2002/04/10 16:59:54  warmerda\n * added SHPRewindObject\n *\n * Revision 1.35  2001/12/07 15:10:44  warmerda\n * fix if .shx fails to open\n *\n * Revision 1.34  2001/11/01 16:29:55  warmerda\n * move pabyRec into SHPInfo for thread safety\n *\n * Revision 1.33  2001/07/03 12:18:15  warmerda\n * Improved cleanup if SHX not found, provied by Riccardo Cohen.\n *\n * Revision 1.32  2001/06/22 01:58:07  warmerda\n * be more careful about establishing initial bounds in face of NULL shapes\n *\n * Revision 1.31  2001/05/31 19:35:29  warmerda\n * added support for writing null shapes\n *\n * Revision 1.30  2001/05/28 12:46:29  warmerda\n * Add some checking on reasonableness of record count when opening.\n *\n * Revision 1.29  2001/05/23 13:36:52  warmerda\n * added use of SHPAPI_CALL\n *\n * Revision 1.28  2001/02/06 22:25:06  warmerda\n * fixed memory leaks when SHPOpen() fails\n *\n * Revision 1.27  2000/07/18 15:21:33  warmerda\n * added better enforcement of -1 for append in SHPWriteObject\n *\n * Revision 1.26  2000/02/16 16:03:51  warmerda\n * added null shape support\n *\n * Revision 1.25  1999/12/15 13:47:07  warmerda\n * Fixed record size settings in .shp file (was 4 words too long)\n * Added stdlib.h.\n *\n * Revision 1.24  1999/11/05 14:12:04  warmerda\n * updated license terms\n *\n * Revision 1.23  1999/07/27 00:53:46  warmerda\n * added support for rewriting shapes\n *\n * Revision 1.22  1999/06/11 19:19:11  warmerda\n * Cleanup pabyRec static buffer on SHPClose().\n *\n * Revision 1.21  1999/06/02 14:57:56  kshih\n * Remove unused variables\n *\n * Revision 1.20  1999/04/19 21:04:17  warmerda\n * Fixed syntax error.\n *\n * Revision 1.19  1999/04/19 21:01:57  warmerda\n * Force access string to binary in SHPOpen().\n *\n * Revision 1.18  1999/04/01 18:48:07  warmerda\n * Try upper case extensions if lower case doesn't work.\n *\n * Revision 1.17  1998/12/31 15:29:39  warmerda\n * Disable writing measure values to multipatch objects if\n * DISABLE_MULTIPATCH_MEASURE is defined.\n *\n * Revision 1.16  1998/12/16 05:14:33  warmerda\n * Added support to write MULTIPATCH.  Fixed reading Z coordinate of\n * MULTIPATCH. Fixed record size written for all feature types.\n *\n * Revision 1.15  1998/12/03 16:35:29  warmerda\n * r+b is proper binary access string, not rb+.\n *\n * Revision 1.14  1998/12/03 15:47:56  warmerda\n * Fixed setting of nVertices in SHPCreateObject().\n *\n * Revision 1.13  1998/12/03 15:33:54  warmerda\n * Made SHPCalculateExtents() separately callable.\n *\n * Revision 1.12  1998/11/11 20:01:50  warmerda\n * Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines.\n *\n * Revision 1.11  1998/11/09 20:56:44  warmerda\n * Fixed up handling of file wide bounds.\n *\n * Revision 1.10  1998/11/09 20:18:51  warmerda\n * Converted to support 3D shapefiles, and use of SHPObject.\n *\n * Revision 1.9  1998/02/24 15:09:05  warmerda\n * Fixed memory leak.\n *\n * Revision 1.8  1997/12/04 15:40:29  warmerda\n * Fixed byte swapping of record number, and record length fields in the\n * .shp file.\n *\n * Revision 1.7  1995/10/21 03:15:58  warmerda\n * Added support for binary file access, the magic cookie 9997\n * and tried to improve the int32 selection logic for 16bit systems.\n *\n * Revision 1.6  1995/09/04  04:19:41  warmerda\n * Added fix for file bounds.\n *\n * Revision 1.5  1995/08/25  15:16:44  warmerda\n * Fixed a couple of problems with big endian systems ... one with bounds\n * and the other with multipart polygons.\n *\n * Revision 1.4  1995/08/24  18:10:17  warmerda\n * Switch to use SfRealloc() to avoid problems with pre-ANSI realloc()\n * functions (such as on the Sun).\n *\n * Revision 1.3  1995/08/23  02:23:15  warmerda\n * Added support for reading bounds, and fixed up problems in setting the\n * file wide bounds.\n *\n * Revision 1.2  1995/08/04  03:16:57  warmerda\n * Added header.\n *\n */\n\n#include \"shapefil.h\"\n\n#include <math.h>\n#include <limits.h>\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n\ntypedef unsigned char uchar;\n\n#if UINT_MAX == 65535\ntypedef long\t      int32;\n#else\ntypedef int\t      int32;\n#endif\n\n#ifndef FALSE\n#  define FALSE\t\t0\n#  define TRUE\t\t1\n#endif\n\n#define ByteCopy( a, b, c )\tmemcpy( b, a, c )\n#ifndef MAX\n#  define MIN(a,b)      ((a<b) ? a : b)\n#  define MAX(a,b)      ((a>b) ? a : b)\n#endif\n\nstatic int \tbBigEndian;\n\n\n/************************************************************************/\n/*                              SwapWord()                              */\n/*                                                                      */\n/*      Swap a 2, 4 or 8 byte word.                                     */\n/************************************************************************/\n\nstatic void\tSwapWord( int length, void * wordP )\n\n{\n    int\t\ti;\n    uchar\ttemp;\n\n    for( i=0; i < length/2; i++ )\n    {\n\ttemp = ((uchar *) wordP)[i];\n\t((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1];\n\t((uchar *) wordP)[length-i-1] = temp;\n    }\n}\n\n/************************************************************************/\n/*                             SfRealloc()                              */\n/*                                                                      */\n/*      A realloc cover function that will access a NULL pointer as     */\n/*      a valid input.                                                  */\n/************************************************************************/\n\nstatic void * SfRealloc( void * pMem, int nNewSize )\n\n{\n    if( pMem == NULL )\n        return( (void *) malloc(nNewSize) );\n    else\n        return( (void *) realloc(pMem,nNewSize) );\n}\n\n/************************************************************************/\n/*                          SHPWriteHeader()                            */\n/*                                                                      */\n/*      Write out a header for the .shp and .shx files as well as the\t*/\n/*\tcontents of the index (.shx) file.\t\t\t\t*/\n/************************************************************************/\n\nvoid SHPWriteHeader( SHPHandle psSHP )\n\n{\n    uchar     \tabyHeader[100];\n    int\t\ti;\n    int32\ti32;\n    double\tdValue;\n    int32\t*panSHX;\n\n/* -------------------------------------------------------------------- */\n/*      Prepare header block for .shp file.                             */\n/* -------------------------------------------------------------------- */\n    for( i = 0; i < 100; i++ )\n      abyHeader[i] = 0;\n\n    abyHeader[2] = 0x27;\t\t\t\t/* magic cookie */\n    abyHeader[3] = 0x0a;\n\n    i32 = psSHP->nFileSize/2;\t\t\t\t/* file size */\n    ByteCopy( &i32, abyHeader+24, 4 );\n    if( !bBigEndian ) SwapWord( 4, abyHeader+24 );\n    \n    i32 = 1000;\t\t\t\t\t\t/* version */\n    ByteCopy( &i32, abyHeader+28, 4 );\n    if( bBigEndian ) SwapWord( 4, abyHeader+28 );\n    \n    i32 = psSHP->nShapeType;\t\t\t\t/* shape type */\n    ByteCopy( &i32, abyHeader+32, 4 );\n    if( bBigEndian ) SwapWord( 4, abyHeader+32 );\n\n    dValue = psSHP->adBoundsMin[0];\t\t\t/* set bounds */\n    ByteCopy( &dValue, abyHeader+36, 8 );\n    if( bBigEndian ) SwapWord( 8, abyHeader+36 );\n\n    dValue = psSHP->adBoundsMin[1];\n    ByteCopy( &dValue, abyHeader+44, 8 );\n    if( bBigEndian ) SwapWord( 8, abyHeader+44 );\n\n    dValue = psSHP->adBoundsMax[0];\n    ByteCopy( &dValue, abyHeader+52, 8 );\n    if( bBigEndian ) SwapWord( 8, abyHeader+52 );\n\n    dValue = psSHP->adBoundsMax[1];\n    ByteCopy( &dValue, abyHeader+60, 8 );\n    if( bBigEndian ) SwapWord( 8, abyHeader+60 );\n\n    dValue = psSHP->adBoundsMin[2];\t\t\t/* z */\n    ByteCopy( &dValue, abyHeader+68, 8 );\n    if( bBigEndian ) SwapWord( 8, abyHeader+68 );\n\n    dValue = psSHP->adBoundsMax[2];\n    ByteCopy( &dValue, abyHeader+76, 8 );\n    if( bBigEndian ) SwapWord( 8, abyHeader+76 );\n\n    dValue = psSHP->adBoundsMin[3];\t\t\t/* m */\n    ByteCopy( &dValue, abyHeader+84, 8 );\n    if( bBigEndian ) SwapWord( 8, abyHeader+84 );\n\n    dValue = psSHP->adBoundsMax[3];\n    ByteCopy( &dValue, abyHeader+92, 8 );\n    if( bBigEndian ) SwapWord( 8, abyHeader+92 );\n\n/* -------------------------------------------------------------------- */\n/*      Write .shp file header.                                         */\n/* -------------------------------------------------------------------- */\n    fseek( psSHP->fpSHP, 0, 0 );\n    fwrite( abyHeader, 100, 1, psSHP->fpSHP );\n\n/* -------------------------------------------------------------------- */\n/*      Prepare, and write .shx file header.                            */\n/* -------------------------------------------------------------------- */\n    i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2;   /* file size */\n    ByteCopy( &i32, abyHeader+24, 4 );\n    if( !bBigEndian ) SwapWord( 4, abyHeader+24 );\n    \n    fseek( psSHP->fpSHX, 0, 0 );\n    fwrite( abyHeader, 100, 1, psSHP->fpSHX );\n\n/* -------------------------------------------------------------------- */\n/*      Write out the .shx contents.                                    */\n/* -------------------------------------------------------------------- */\n    panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);\n\n    for( i = 0; i < psSHP->nRecords; i++ )\n    {\n\tpanSHX[i*2  ] = psSHP->panRecOffset[i]/2;\n\tpanSHX[i*2+1] = psSHP->panRecSize[i]/2;\n\tif( !bBigEndian ) SwapWord( 4, panSHX+i*2 );\n\tif( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );\n    }\n\n    fwrite( panSHX, sizeof(int32) * 2, psSHP->nRecords, psSHP->fpSHX );\n\n    free( panSHX );\n\n/* -------------------------------------------------------------------- */\n/*      Flush to disk.                                                  */\n/* -------------------------------------------------------------------- */\n    fflush( psSHP->fpSHP );\n    fflush( psSHP->fpSHX );\n}\n\n/************************************************************************/\n/*                              SHPOpen()                               */\n/*                                                                      */\n/*      Open the .shp and .shx files based on the basename of the       */\n/*      files or either file name.                                      */\n/************************************************************************/\n   \nSHPHandle SHPAPI_CALL\nSHPOpen( const char * pszLayer, const char * pszAccess )\n\n{\n    char\t\t*pszFullname, *pszBasename;\n    SHPHandle\t\tpsSHP;\n    \n    uchar\t\t*pabyBuf;\n    int\t\t\ti;\n    double\t\tdValue;\n    \n/* -------------------------------------------------------------------- */\n/*      Ensure the access string is one of the legal ones.  We          */\n/*      ensure the result string indicates binary to avoid common       */\n/*      problems on Windows.                                            */\n/* -------------------------------------------------------------------- */\n    if( strcmp(pszAccess,\"rb+\") == 0 || strcmp(pszAccess,\"r+b\") == 0\n        || strcmp(pszAccess,\"r+\") == 0 )\n        pszAccess = \"r+b\";\n    else\n        pszAccess = \"rb\";\n    \n/* -------------------------------------------------------------------- */\n/*\tEstablish the byte order on this machine.\t\t\t*/\n/* -------------------------------------------------------------------- */\n    i = 1;\n    if( *((uchar *) &i) == 1 )\n        bBigEndian = FALSE;\n    else\n        bBigEndian = TRUE;\n\n/* -------------------------------------------------------------------- */\n/*\tInitialize the info structure.\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);\n\n    psSHP->bUpdated = FALSE;\n\n/* -------------------------------------------------------------------- */\n/*\tCompute the base (layer) name.  If there is any extension\t*/\n/*\ton the passed in filename we will strip it off.\t\t\t*/\n/* -------------------------------------------------------------------- */\n    pszBasename = (char *) malloc(strlen(pszLayer)+5);\n    strcpy( pszBasename, pszLayer );\n    for( i = strlen(pszBasename)-1; \n\t i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'\n\t       && pszBasename[i] != '\\\\';\n\t i-- ) {}\n\n    if( pszBasename[i] == '.' )\n        pszBasename[i] = '\\0';\n\n/* -------------------------------------------------------------------- */\n/*\tOpen the .shp and .shx files.  Note that files pulled from\t*/\n/*\ta PC to Unix with upper case filenames won't work!\t\t*/\n/* -------------------------------------------------------------------- */\n    pszFullname = (char *) malloc(strlen(pszBasename) + 5);\n    sprintf( pszFullname, \"%s.shp\", pszBasename );\n    psSHP->fpSHP = fopen(pszFullname, pszAccess );\n    if( psSHP->fpSHP == NULL )\n    {\n        sprintf( pszFullname, \"%s.SHP\", pszBasename );\n        psSHP->fpSHP = fopen(pszFullname, pszAccess );\n    }\n    \n    if( psSHP->fpSHP == NULL )\n    {\n        free( psSHP );\n        free( pszBasename );\n        free( pszFullname );\n        return( NULL );\n    }\n\n    sprintf( pszFullname, \"%s.shx\", pszBasename );\n    psSHP->fpSHX = fopen(pszFullname, pszAccess );\n    if( psSHP->fpSHX == NULL )\n    {\n        sprintf( pszFullname, \"%s.SHX\", pszBasename );\n        psSHP->fpSHX = fopen(pszFullname, pszAccess );\n    }\n    \n    if( psSHP->fpSHX == NULL )\n    {\n        fclose( psSHP->fpSHP );\n        free( psSHP );\n        free( pszBasename );\n        free( pszFullname );\n        return( NULL );\n    }\n\n    free( pszFullname );\n    free( pszBasename );\n\n/* -------------------------------------------------------------------- */\n/*  Read the file size from the SHP file.\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    pabyBuf = (uchar *) malloc(100);\n    fread( pabyBuf, 100, 1, psSHP->fpSHP );\n\n    psSHP->nFileSize = (pabyBuf[24] * 256 * 256 * 256\n\t\t\t+ pabyBuf[25] * 256 * 256\n\t\t\t+ pabyBuf[26] * 256\n\t\t\t+ pabyBuf[27]) * 2;\n\n/* -------------------------------------------------------------------- */\n/*  Read SHX file Header info                                           */\n/* -------------------------------------------------------------------- */\n    fread( pabyBuf, 100, 1, psSHP->fpSHX );\n\n    if( pabyBuf[0] != 0 \n        || pabyBuf[1] != 0 \n        || pabyBuf[2] != 0x27 \n        || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )\n    {\n\tfclose( psSHP->fpSHP );\n\tfclose( psSHP->fpSHX );\n\tfree( psSHP );\n\n\treturn( NULL );\n    }\n\n    psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256\n      + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;\n    psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;\n\n    psSHP->nShapeType = pabyBuf[32];\n\n    if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )\n    {\n        /* this header appears to be corrupt.  Give up. */\n\tfclose( psSHP->fpSHP );\n\tfclose( psSHP->fpSHX );\n\tfree( psSHP );\n\n\treturn( NULL );\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Read the bounds.                                                */\n/* -------------------------------------------------------------------- */\n    if( bBigEndian ) SwapWord( 8, pabyBuf+36 );\n    memcpy( &dValue, pabyBuf+36, 8 );\n    psSHP->adBoundsMin[0] = dValue;\n\n    if( bBigEndian ) SwapWord( 8, pabyBuf+44 );\n    memcpy( &dValue, pabyBuf+44, 8 );\n    psSHP->adBoundsMin[1] = dValue;\n\n    if( bBigEndian ) SwapWord( 8, pabyBuf+52 );\n    memcpy( &dValue, pabyBuf+52, 8 );\n    psSHP->adBoundsMax[0] = dValue;\n\n    if( bBigEndian ) SwapWord( 8, pabyBuf+60 );\n    memcpy( &dValue, pabyBuf+60, 8 );\n    psSHP->adBoundsMax[1] = dValue;\n\n    if( bBigEndian ) SwapWord( 8, pabyBuf+68 );\t\t/* z */\n    memcpy( &dValue, pabyBuf+68, 8 );\n    psSHP->adBoundsMin[2] = dValue;\n    \n    if( bBigEndian ) SwapWord( 8, pabyBuf+76 );\n    memcpy( &dValue, pabyBuf+76, 8 );\n    psSHP->adBoundsMax[2] = dValue;\n    \n    if( bBigEndian ) SwapWord( 8, pabyBuf+84 );\t\t/* z */\n    memcpy( &dValue, pabyBuf+84, 8 );\n    psSHP->adBoundsMin[3] = dValue;\n\n    if( bBigEndian ) SwapWord( 8, pabyBuf+92 );\n    memcpy( &dValue, pabyBuf+92, 8 );\n    psSHP->adBoundsMax[3] = dValue;\n\n    free( pabyBuf );\n\n/* -------------------------------------------------------------------- */\n/*\tRead the .shx file to get the offsets to each record in \t*/\n/*\tthe .shp file.\t\t\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    psSHP->nMaxRecords = psSHP->nRecords;\n\n    psSHP->panRecOffset =\n        (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );\n    psSHP->panRecSize =\n        (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );\n\n    pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );\n    fread( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX );\n\n    for( i = 0; i < psSHP->nRecords; i++ )\n    {\n\tint32\t\tnOffset, nLength;\n\n\tmemcpy( &nOffset, pabyBuf + i * 8, 4 );\n\tif( !bBigEndian ) SwapWord( 4, &nOffset );\n\n\tmemcpy( &nLength, pabyBuf + i * 8 + 4, 4 );\n\tif( !bBigEndian ) SwapWord( 4, &nLength );\n\n\tpsSHP->panRecOffset[i] = nOffset*2;\n\tpsSHP->panRecSize[i] = nLength*2;\n    }\n    free( pabyBuf );\n\n    return( psSHP );\n}\n\n/************************************************************************/\n/*                              SHPClose()                              */\n/*\t\t\t\t\t\t\t\t       \t*/\n/*\tClose the .shp and .shx files.\t\t\t\t\t*/\n/************************************************************************/\n\nvoid SHPAPI_CALL\nSHPClose(SHPHandle psSHP )\n\n{\n/* -------------------------------------------------------------------- */\n/*\tUpdate the header if we have modified anything.\t\t\t*/\n/* -------------------------------------------------------------------- */\n    if( psSHP->bUpdated )\n\tSHPWriteHeader( psSHP );\n\n/* -------------------------------------------------------------------- */\n/*      Free all resources, and close files.                            */\n/* -------------------------------------------------------------------- */\n    free( psSHP->panRecOffset );\n    free( psSHP->panRecSize );\n\n    fclose( psSHP->fpSHX );\n    fclose( psSHP->fpSHP );\n\n    if( psSHP->pabyRec != NULL )\n    {\n        free( psSHP->pabyRec );\n    }\n    \n    free( psSHP );\n}\n\n/************************************************************************/\n/*                             SHPGetInfo()                             */\n/*                                                                      */\n/*      Fetch general information about the shape file.                 */\n/************************************************************************/\n\nvoid SHPAPI_CALL\nSHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,\n           double * padfMinBound, double * padfMaxBound )\n\n{\n    int\t\ti;\n    \n    if( pnEntities != NULL )\n        *pnEntities = psSHP->nRecords;\n\n    if( pnShapeType != NULL )\n        *pnShapeType = psSHP->nShapeType;\n\n    for( i = 0; i < 4; i++ )\n    {\n        if( padfMinBound != NULL )\n            padfMinBound[i] = psSHP->adBoundsMin[i];\n        if( padfMaxBound != NULL )\n            padfMaxBound[i] = psSHP->adBoundsMax[i];\n    }\n}\n\n/************************************************************************/\n/*                             SHPCreate()                              */\n/*                                                                      */\n/*      Create a new shape file and return a handle to the open         */\n/*      shape file with read/write access.                              */\n/************************************************************************/\n\nSHPHandle SHPAPI_CALL\nSHPCreate( const char * pszLayer, int nShapeType )\n\n{\n    char\t*pszBasename, *pszFullname;\n    int\t\ti;\n    FILE\t*fpSHP, *fpSHX;\n    uchar     \tabyHeader[100];\n    int32\ti32;\n    double\tdValue;\n    \n/* -------------------------------------------------------------------- */\n/*      Establish the byte order on this system.                        */\n/* -------------------------------------------------------------------- */\n    i = 1;\n    if( *((uchar *) &i) == 1 )\n        bBigEndian = FALSE;\n    else\n        bBigEndian = TRUE;\n\n/* -------------------------------------------------------------------- */\n/*\tCompute the base (layer) name.  If there is any extension\t*/\n/*\ton the passed in filename we will strip it off.\t\t\t*/\n/* -------------------------------------------------------------------- */\n    pszBasename = (char *) malloc(strlen(pszLayer)+5);\n    strcpy( pszBasename, pszLayer );\n    for( i = strlen(pszBasename)-1; \n\t i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'\n\t       && pszBasename[i] != '\\\\';\n\t i-- ) {}\n\n    if( pszBasename[i] == '.' )\n        pszBasename[i] = '\\0';\n\n/* -------------------------------------------------------------------- */\n/*      Open the two files so we can write their headers.               */\n/* -------------------------------------------------------------------- */\n    pszFullname = (char *) malloc(strlen(pszBasename) + 5);\n    sprintf( pszFullname, \"%s.shp\", pszBasename );\n    fpSHP = fopen(pszFullname, \"wb\" );\n    if( fpSHP == NULL )\n        return( NULL );\n\n    sprintf( pszFullname, \"%s.shx\", pszBasename );\n    fpSHX = fopen(pszFullname, \"wb\" );\n    if( fpSHX == NULL )\n        return( NULL );\n\n    free( pszFullname );\n    free( pszBasename );\n\n/* -------------------------------------------------------------------- */\n/*      Prepare header block for .shp file.                             */\n/* -------------------------------------------------------------------- */\n    for( i = 0; i < 100; i++ )\n      abyHeader[i] = 0;\n\n    abyHeader[2] = 0x27;\t\t\t\t/* magic cookie */\n    abyHeader[3] = 0x0a;\n\n    i32 = 50;\t\t\t\t\t\t/* file size */\n    ByteCopy( &i32, abyHeader+24, 4 );\n    if( !bBigEndian ) SwapWord( 4, abyHeader+24 );\n    \n    i32 = 1000;\t\t\t\t\t\t/* version */\n    ByteCopy( &i32, abyHeader+28, 4 );\n    if( bBigEndian ) SwapWord( 4, abyHeader+28 );\n    \n    i32 = nShapeType;\t\t\t\t\t/* shape type */\n    ByteCopy( &i32, abyHeader+32, 4 );\n    if( bBigEndian ) SwapWord( 4, abyHeader+32 );\n\n    dValue = 0.0;\t\t\t\t\t/* set bounds */\n    ByteCopy( &dValue, abyHeader+36, 8 );\n    ByteCopy( &dValue, abyHeader+44, 8 );\n    ByteCopy( &dValue, abyHeader+52, 8 );\n    ByteCopy( &dValue, abyHeader+60, 8 );\n\n/* -------------------------------------------------------------------- */\n/*      Write .shp file header.                                         */\n/* -------------------------------------------------------------------- */\n    fwrite( abyHeader, 100, 1, fpSHP );\n\n/* -------------------------------------------------------------------- */\n/*      Prepare, and write .shx file header.                            */\n/* -------------------------------------------------------------------- */\n    i32 = 50;\t\t\t\t\t\t/* file size */\n    ByteCopy( &i32, abyHeader+24, 4 );\n    if( !bBigEndian ) SwapWord( 4, abyHeader+24 );\n    \n    fwrite( abyHeader, 100, 1, fpSHX );\n\n/* -------------------------------------------------------------------- */\n/*      Close the files, and then open them as regular existing files.  */\n/* -------------------------------------------------------------------- */\n    fclose( fpSHP );\n    fclose( fpSHX );\n\n    return( SHPOpen( pszLayer, \"r+b\" ) );\n}\n\n/************************************************************************/\n/*                           _SHPSetBounds()                            */\n/*                                                                      */\n/*      Compute a bounds rectangle for a shape, and set it into the     */\n/*      indicated location in the record.                               */\n/************************************************************************/\n\nstatic void\t_SHPSetBounds( uchar * pabyRec, SHPObject * psShape )\n\n{\n    ByteCopy( &(psShape->dfXMin), pabyRec +  0, 8 );\n    ByteCopy( &(psShape->dfYMin), pabyRec +  8, 8 );\n    ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 );\n    ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 );\n\n    if( bBigEndian )\n    {\n        SwapWord( 8, pabyRec + 0 );\n        SwapWord( 8, pabyRec + 8 );\n        SwapWord( 8, pabyRec + 16 );\n        SwapWord( 8, pabyRec + 24 );\n    }\n}\n\n/************************************************************************/\n/*                         SHPComputeExtents()                          */\n/*                                                                      */\n/*      Recompute the extents of a shape.  Automatically done by        */\n/*      SHPCreateObject().                                              */\n/************************************************************************/\n\nvoid SHPAPI_CALL\nSHPComputeExtents( SHPObject * psObject )\n\n{\n    int\t\ti;\n    \n/* -------------------------------------------------------------------- */\n/*      Build extents for this object.                                  */\n/* -------------------------------------------------------------------- */\n    if( psObject->nVertices > 0 )\n    {\n        psObject->dfXMin = psObject->dfXMax = psObject->padfX[0];\n        psObject->dfYMin = psObject->dfYMax = psObject->padfY[0];\n        psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];\n        psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];\n    }\n    \n    for( i = 0; i < psObject->nVertices; i++ )\n    {\n        psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);\n        psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]);\n        psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]);\n        psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]);\n\n        psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]);\n        psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]);\n        psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]);\n        psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]);\n    }\n}\n\n/************************************************************************/\n/*                          SHPCreateObject()                           */\n/*                                                                      */\n/*      Create a shape object.  It should be freed with                 */\n/*      SHPDestroyObject().                                             */\n/************************************************************************/\n\nSHPObject SHPAPI_CALL1(*)\nSHPCreateObject( int nSHPType, int nShapeId, int nParts,\n                 int * panPartStart, int * panPartType,\n                 int nVertices, double * padfX, double * padfY,\n                 double * padfZ, double * padfM )\n\n{\n    SHPObject\t*psObject;\n    int\t\ti, bHasM, bHasZ;\n\n    psObject = (SHPObject *) calloc(1,sizeof(SHPObject));\n    psObject->nSHPType = nSHPType;\n    psObject->nShapeId = nShapeId;\n\n/* -------------------------------------------------------------------- */\n/*\tEstablish whether this shape type has M, and Z values.\t\t*/\n/* -------------------------------------------------------------------- */\n    if( nSHPType == SHPT_ARCM\n        || nSHPType == SHPT_POINTM\n        || nSHPType == SHPT_POLYGONM\n        || nSHPType == SHPT_MULTIPOINTM )\n    {\n        bHasM = TRUE;\n        bHasZ = FALSE;\n    }\n    else if( nSHPType == SHPT_ARCZ\n             || nSHPType == SHPT_POINTZ\n             || nSHPType == SHPT_POLYGONZ\n             || nSHPType == SHPT_MULTIPOINTZ\n             || nSHPType == SHPT_MULTIPATCH )\n    {\n        bHasM = TRUE;\n        bHasZ = TRUE;\n    }\n    else\n    {\n        bHasM = FALSE;\n        bHasZ = FALSE;\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Capture parts.  Note that part type is optional, and            */\n/*      defaults to ring.                                               */\n/* -------------------------------------------------------------------- */\n    if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON\n        || nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM\n        || nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ\n        || nSHPType == SHPT_MULTIPATCH )\n    {\n        psObject->nParts = MAX(1,nParts);\n\n        psObject->panPartStart = (int *)\n            malloc(sizeof(int) * psObject->nParts);\n        psObject->panPartType = (int *)\n            malloc(sizeof(int) * psObject->nParts);\n\n        psObject->panPartStart[0] = 0;\n        psObject->panPartType[0] = SHPP_RING;\n        \n        for( i = 0; i < nParts; i++ )\n        {\n            psObject->panPartStart[i] = panPartStart[i];\n            if( panPartType != NULL )\n                psObject->panPartType[i] = panPartType[i];\n            else\n                psObject->panPartType[i] = SHPP_RING;\n        }\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Capture vertices.  Note that Z and M are optional, but X and    */\n/*      Y are not.                                                      */\n/* -------------------------------------------------------------------- */\n    if( nVertices > 0 )\n    {\n        psObject->padfX = (double *) calloc(sizeof(double),nVertices);\n        psObject->padfY = (double *) calloc(sizeof(double),nVertices);\n        psObject->padfZ = (double *) calloc(sizeof(double),nVertices);\n        psObject->padfM = (double *) calloc(sizeof(double),nVertices);\n\n        assert( padfX != NULL );\n        assert( padfY != NULL );\n    \n        for( i = 0; i < nVertices; i++ )\n        {\n            psObject->padfX[i] = padfX[i];\n            psObject->padfY[i] = padfY[i];\n            if( padfZ != NULL && bHasZ )\n                psObject->padfZ[i] = padfZ[i];\n            if( padfM != NULL && bHasM )\n                psObject->padfM[i] = padfM[i];\n        }\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Compute the extents.                                            */\n/* -------------------------------------------------------------------- */\n    psObject->nVertices = nVertices;\n    SHPComputeExtents( psObject );\n\n    return( psObject );\n}\n\n/************************************************************************/\n/*                       SHPCreateSimpleObject()                        */\n/*                                                                      */\n/*      Create a simple (common) shape object.  Destroy with            */\n/*      SHPDestroyObject().                                             */\n/************************************************************************/\n\nSHPObject SHPAPI_CALL1(*)\nSHPCreateSimpleObject( int nSHPType, int nVertices,\n                       double * padfX, double * padfY,\n                       double * padfZ )\n\n{\n    return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,\n                             nVertices, padfX, padfY, padfZ, NULL ) );\n}\n                                  \n/************************************************************************/\n/*                           SHPWriteObject()                           */\n/*                                                                      */\n/*      Write out the vertices of a new structure.  Note that it is     */\n/*      only possible to write vertices at the end of the file.         */\n/************************************************************************/\n\nint SHPAPI_CALL\nSHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )\n\t\t      \n{\n    int\t       \tnRecordOffset, i, nRecordSize=0;\n    uchar\t*pabyRec;\n    int32\ti32;\n\n    psSHP->bUpdated = TRUE;\n\n/* -------------------------------------------------------------------- */\n/*      Ensure that shape object matches the type of the file it is     */\n/*      being written to.                                               */\n/* -------------------------------------------------------------------- */\n    assert( psObject->nSHPType == psSHP->nShapeType \n            || psObject->nSHPType == SHPT_NULL );\n\n/* -------------------------------------------------------------------- */\n/*      Ensure that -1 is used for appends.  Either blow an             */\n/*      assertion, or if they are disabled, set the shapeid to -1       */\n/*      for appends.                                                    */\n/* -------------------------------------------------------------------- */\n    assert( nShapeId == -1 \n            || (nShapeId >= 0 && nShapeId < psSHP->nRecords) );\n\n    if( nShapeId != -1 && nShapeId >= psSHP->nRecords )\n        nShapeId = -1;\n\n/* -------------------------------------------------------------------- */\n/*      Add the new entity to the in memory index.                      */\n/* -------------------------------------------------------------------- */\n    if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )\n    {\n\tpsSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);\n\n\tpsSHP->panRecOffset = (int *) \n            SfRealloc(psSHP->panRecOffset,sizeof(int) * psSHP->nMaxRecords );\n\tpsSHP->panRecSize = (int *) \n            SfRealloc(psSHP->panRecSize,sizeof(int) * psSHP->nMaxRecords );\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Initialize record.                                              */\n/* -------------------------------------------------------------------- */\n    pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double) \n\t\t\t       + psObject->nParts * 8 + 128);\n    \n/* -------------------------------------------------------------------- */\n/*  Extract vertices for a Polygon or Arc.\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    if( psObject->nSHPType == SHPT_POLYGON\n        || psObject->nSHPType == SHPT_POLYGONZ\n        || psObject->nSHPType == SHPT_POLYGONM\n        || psObject->nSHPType == SHPT_ARC \n        || psObject->nSHPType == SHPT_ARCZ\n        || psObject->nSHPType == SHPT_ARCM\n        || psObject->nSHPType == SHPT_MULTIPATCH )\n    {\n\tint32\t\tnPoints, nParts;\n\tint    \t\ti;\n\n\tnPoints = psObject->nVertices;\n\tnParts = psObject->nParts;\n\n\t_SHPSetBounds( pabyRec + 12, psObject );\n\n\tif( bBigEndian ) SwapWord( 4, &nPoints );\n\tif( bBigEndian ) SwapWord( 4, &nParts );\n\n\tByteCopy( &nPoints, pabyRec + 40 + 8, 4 );\n\tByteCopy( &nParts, pabyRec + 36 + 8, 4 );\n\n        nRecordSize = 52;\n\n        /*\n         * Write part start positions.\n         */\n\tByteCopy( psObject->panPartStart, pabyRec + 44 + 8,\n                  4 * psObject->nParts );\n\tfor( i = 0; i < psObject->nParts; i++ )\n\t{\n\t    if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );\n            nRecordSize += 4;\n\t}\n\n        /*\n         * Write multipatch part types if needed.\n         */\n        if( psObject->nSHPType == SHPT_MULTIPATCH )\n        {\n            memcpy( pabyRec + nRecordSize, psObject->panPartType,\n                    4*psObject->nParts );\n            for( i = 0; i < psObject->nParts; i++ )\n            {\n                if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize );\n                nRecordSize += 4;\n            }\n        }\n\n        /*\n         * Write the (x,y) vertex values.\n         */\n\tfor( i = 0; i < psObject->nVertices; i++ )\n\t{\n\t    ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );\n\t    ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );\n\n\t    if( bBigEndian )\n                SwapWord( 8, pabyRec + nRecordSize );\n            \n\t    if( bBigEndian )\n                SwapWord( 8, pabyRec + nRecordSize + 8 );\n\n            nRecordSize += 2 * 8;\n\t}\n\n        /*\n         * Write the Z coordinates (if any).\n         */\n        if( psObject->nSHPType == SHPT_POLYGONZ\n            || psObject->nSHPType == SHPT_ARCZ\n            || psObject->nSHPType == SHPT_MULTIPATCH )\n        {\n            ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );\n            if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n            nRecordSize += 8;\n            \n            ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );\n            if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n            nRecordSize += 8;\n\n            for( i = 0; i < psObject->nVertices; i++ )\n            {\n                ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );\n                if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n                nRecordSize += 8;\n            }\n        }\n\n        /*\n         * Write the M values, if any.\n         */\n        if( psObject->nSHPType == SHPT_POLYGONM\n            || psObject->nSHPType == SHPT_ARCM\n#ifndef DISABLE_MULTIPATCH_MEASURE            \n            || psObject->nSHPType == SHPT_MULTIPATCH\n#endif            \n            || psObject->nSHPType == SHPT_POLYGONZ\n            || psObject->nSHPType == SHPT_ARCZ )\n        {\n            ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );\n            if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n            nRecordSize += 8;\n            \n            ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );\n            if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n            nRecordSize += 8;\n\n            for( i = 0; i < psObject->nVertices; i++ )\n            {\n                ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );\n                if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n                nRecordSize += 8;\n            }\n        }\n    }\n\n/* -------------------------------------------------------------------- */\n/*  Extract vertices for a MultiPoint.\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    else if( psObject->nSHPType == SHPT_MULTIPOINT\n             || psObject->nSHPType == SHPT_MULTIPOINTZ\n             || psObject->nSHPType == SHPT_MULTIPOINTM )\n    {\n\tint32\t\tnPoints;\n\tint    \t\ti;\n\n\tnPoints = psObject->nVertices;\n\n        _SHPSetBounds( pabyRec + 12, psObject );\n\n\tif( bBigEndian ) SwapWord( 4, &nPoints );\n\tByteCopy( &nPoints, pabyRec + 44, 4 );\n\t\n\tfor( i = 0; i < psObject->nVertices; i++ )\n\t{\n\t    ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );\n\t    ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );\n\n\t    if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );\n\t    if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );\n\t}\n\n\tnRecordSize = 48 + 16 * psObject->nVertices;\n\n        if( psObject->nSHPType == SHPT_MULTIPOINTZ )\n        {\n            ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );\n            if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n            nRecordSize += 8;\n\n            ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );\n            if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n            nRecordSize += 8;\n            \n            for( i = 0; i < psObject->nVertices; i++ )\n            {\n                ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );\n                if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n                nRecordSize += 8;\n            }\n        }\n\n        if( psObject->nSHPType == SHPT_MULTIPOINTZ\n            || psObject->nSHPType == SHPT_MULTIPOINTM )\n        {\n            ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );\n            if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n            nRecordSize += 8;\n\n            ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );\n            if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n            nRecordSize += 8;\n            \n            for( i = 0; i < psObject->nVertices; i++ )\n            {\n                ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );\n                if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n                nRecordSize += 8;\n            }\n        }\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Write point.\t\t\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n    else if( psObject->nSHPType == SHPT_POINT\n             || psObject->nSHPType == SHPT_POINTZ\n             || psObject->nSHPType == SHPT_POINTM )\n    {\n\tByteCopy( psObject->padfX, pabyRec + 12, 8 );\n\tByteCopy( psObject->padfY, pabyRec + 20, 8 );\n\n\tif( bBigEndian ) SwapWord( 8, pabyRec + 12 );\n\tif( bBigEndian ) SwapWord( 8, pabyRec + 20 );\n\n        nRecordSize = 28;\n        \n        if( psObject->nSHPType == SHPT_POINTZ )\n        {\n            ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );\n            if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n            nRecordSize += 8;\n        }\n        \n        if( psObject->nSHPType == SHPT_POINTZ\n            || psObject->nSHPType == SHPT_POINTM )\n        {\n            ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );\n            if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );\n            nRecordSize += 8;\n        }\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Not much to do for null geometries.                             */\n/* -------------------------------------------------------------------- */\n    else if( psObject->nSHPType == SHPT_NULL )\n    {\n        nRecordSize = 12;\n    }\n\n    else\n    {\n        /* unknown type */\n        assert( FALSE );\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Establish where we are going to put this record. If we are      */\n/*      rewriting and existing record, and it will fit, then put it     */\n/*      back where the original came from.  Otherwise write at the end. */\n/* -------------------------------------------------------------------- */\n    if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )\n    {\n        if( nShapeId == -1 )\n            nShapeId = psSHP->nRecords++;\n\n        psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;\n        psSHP->panRecSize[nShapeId] = nRecordSize-8;\n        psSHP->nFileSize += nRecordSize;\n    }\n    else\n    {\n        nRecordOffset = psSHP->panRecOffset[nShapeId];\n    }\n    \n/* -------------------------------------------------------------------- */\n/*      Set the shape type, record number, and record size.             */\n/* -------------------------------------------------------------------- */\n    i32 = nShapeId+1;\t\t\t\t\t/* record # */\n    if( !bBigEndian ) SwapWord( 4, &i32 );\n    ByteCopy( &i32, pabyRec, 4 );\n\n    i32 = (nRecordSize-8)/2;\t\t\t\t/* record size */\n    if( !bBigEndian ) SwapWord( 4, &i32 );\n    ByteCopy( &i32, pabyRec + 4, 4 );\n\n    i32 = psObject->nSHPType;\t\t\t\t/* shape type */\n    if( bBigEndian ) SwapWord( 4, &i32 );\n    ByteCopy( &i32, pabyRec + 8, 4 );\n\n/* -------------------------------------------------------------------- */\n/*      Write out record.                                               */\n/* -------------------------------------------------------------------- */\n    if( fseek( psSHP->fpSHP, nRecordOffset, 0 ) != 0\n        || fwrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )\n    {\n        printf( \"Error in fseek() or fwrite().\\n\" );\n        free( pabyRec );\n        return -1;\n    }\n    \n    free( pabyRec );\n\n/* -------------------------------------------------------------------- */\n/*\tExpand file wide bounds based on this shape.\t\t\t*/\n/* -------------------------------------------------------------------- */\n    if( psSHP->adBoundsMin[0] == 0.0\n        && psSHP->adBoundsMax[0] == 0.0\n        && psSHP->adBoundsMin[1] == 0.0\n        && psSHP->adBoundsMax[1] == 0.0 )\n    {\n        if( psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0 )\n        {\n            psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0;\n            psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0;\n            psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0;\n            psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0;\n        }\n        else\n        {\n            psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];\n            psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];\n            psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];\n            psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];\n        }\n    }\n\n    for( i = 0; i < psObject->nVertices; i++ )\n    {\n\tpsSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);\n\tpsSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);\n\tpsSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);\n\tpsSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);\n\tpsSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);\n\tpsSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);\n\tpsSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);\n\tpsSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);\n    }\n\n    return( nShapeId  );\n}\n\n/************************************************************************/\n/*                          SHPReadObject()                             */\n/*                                                                      */\n/*      Read the vertices, parts, and other non-attribute information\t*/\n/*\tfor one shape.\t\t\t\t\t\t\t*/\n/************************************************************************/\n\nSHPObject SHPAPI_CALL1(*)\nSHPReadObject( SHPHandle psSHP, int hEntity )\n\n{\n    SHPObject\t\t*psShape;\n\n/* -------------------------------------------------------------------- */\n/*      Validate the record/entity number.                              */\n/* -------------------------------------------------------------------- */\n    if( hEntity < 0 || hEntity >= psSHP->nRecords )\n        return( NULL );\n\n/* -------------------------------------------------------------------- */\n/*      Ensure our record buffer is large enough.                       */\n/* -------------------------------------------------------------------- */\n    if( psSHP->panRecSize[hEntity]+8 > psSHP->nBufSize )\n    {\n\tpsSHP->nBufSize = psSHP->panRecSize[hEntity]+8;\n\tpsSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize);\n    }\n\n/* -------------------------------------------------------------------- */\n/*      Read the record.                                                */\n/* -------------------------------------------------------------------- */\n    fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 );\n    fread( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP );\n\n/* -------------------------------------------------------------------- */\n/*\tAllocate and minimally initialize the object.\t\t\t*/\n/* -------------------------------------------------------------------- */\n    psShape = (SHPObject *) calloc(1,sizeof(SHPObject));\n    psShape->nShapeId = hEntity;\n\n    memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );\n    if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );\n\n/* ==================================================================== */\n/*  Extract vertices for a Polygon or Arc.\t\t\t\t*/\n/* ==================================================================== */\n    if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC\n        || psShape->nSHPType == SHPT_POLYGONZ\n        || psShape->nSHPType == SHPT_POLYGONM\n        || psShape->nSHPType == SHPT_ARCZ\n        || psShape->nSHPType == SHPT_ARCM\n        || psShape->nSHPType == SHPT_MULTIPATCH )\n    {\n\tint32\t\tnPoints, nParts;\n\tint    \t\ti, nOffset;\n\n/* -------------------------------------------------------------------- */\n/*\tGet the X/Y bounds.\t\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n        memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 +  4, 8 );\n        memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );\n        memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );\n        memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );\n\n\tif( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );\n\tif( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );\n\tif( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );\n\tif( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );\n\n/* -------------------------------------------------------------------- */\n/*      Extract part/point count, and build vertex and part arrays      */\n/*      to proper size.                                                 */\n/* -------------------------------------------------------------------- */\n\tmemcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );\n\tmemcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );\n\n\tif( bBigEndian ) SwapWord( 4, &nPoints );\n\tif( bBigEndian ) SwapWord( 4, &nParts );\n\n\tpsShape->nVertices = nPoints;\n        psShape->padfX = (double *) calloc(nPoints,sizeof(double));\n        psShape->padfY = (double *) calloc(nPoints,sizeof(double));\n        psShape->padfZ = (double *) calloc(nPoints,sizeof(double));\n        psShape->padfM = (double *) calloc(nPoints,sizeof(double));\n\n\tpsShape->nParts = nParts;\n        psShape->panPartStart = (int *) calloc(nParts,sizeof(int));\n        psShape->panPartType = (int *) calloc(nParts,sizeof(int));\n\n        for( i = 0; i < nParts; i++ )\n            psShape->panPartType[i] = SHPP_RING;\n\n/* -------------------------------------------------------------------- */\n/*      Copy out the part array from the record.                        */\n/* -------------------------------------------------------------------- */\n\tmemcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );\n\tfor( i = 0; i < nParts; i++ )\n\t{\n\t    if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );\n\t}\n\n\tnOffset = 44 + 8 + 4*nParts;\n\n/* -------------------------------------------------------------------- */\n/*      If this is a multipatch, we will also have parts types.         */\n/* -------------------------------------------------------------------- */\n        if( psShape->nSHPType == SHPT_MULTIPATCH )\n        {\n            memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );\n            for( i = 0; i < nParts; i++ )\n            {\n                if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );\n            }\n\n            nOffset += 4*nParts;\n        }\n        \n/* -------------------------------------------------------------------- */\n/*      Copy out the vertices from the record.                          */\n/* -------------------------------------------------------------------- */\n\tfor( i = 0; i < nPoints; i++ )\n\t{\n\t    memcpy(psShape->padfX + i,\n\t\t   psSHP->pabyRec + nOffset + i * 16,\n\t\t   8 );\n\n\t    memcpy(psShape->padfY + i,\n\t\t   psSHP->pabyRec + nOffset + i * 16 + 8,\n\t\t   8 );\n\n\t    if( bBigEndian ) SwapWord( 8, psShape->padfX + i );\n\t    if( bBigEndian ) SwapWord( 8, psShape->padfY + i );\n\t}\n\n        nOffset += 16*nPoints;\n        \n/* -------------------------------------------------------------------- */\n/*      If we have a Z coordinate, collect that now.                    */\n/* -------------------------------------------------------------------- */\n        if( psShape->nSHPType == SHPT_POLYGONZ\n            || psShape->nSHPType == SHPT_ARCZ\n            || psShape->nSHPType == SHPT_MULTIPATCH )\n        {\n            memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );\n            memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );\n            \n            if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );\n            if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );\n            \n            for( i = 0; i < nPoints; i++ )\n            {\n                memcpy( psShape->padfZ + i,\n                        psSHP->pabyRec + nOffset + 16 + i*8, 8 );\n                if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );\n            }\n\n            nOffset += 16 + 8*nPoints;\n        }\n\n/* -------------------------------------------------------------------- */\n/*      If we have a M measure value, then read it now.  We assume      */\n/*      that the measure can be present for any shape if the size is    */\n/*      big enough, but really it will only occur for the Z shapes      */\n/*      (options), and the M shapes.                                    */\n/* -------------------------------------------------------------------- */\n        if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )\n        {\n            memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );\n            memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );\n            \n            if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );\n            if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );\n            \n            for( i = 0; i < nPoints; i++ )\n            {\n                memcpy( psShape->padfM + i,\n                        psSHP->pabyRec + nOffset + 16 + i*8, 8 );\n                if( bBigEndian ) SwapWord( 8, psShape->padfM + i );\n            }\n        }\n        \n    }\n\n/* ==================================================================== */\n/*  Extract vertices for a MultiPoint.\t\t\t\t\t*/\n/* ==================================================================== */\n    else if( psShape->nSHPType == SHPT_MULTIPOINT\n             || psShape->nSHPType == SHPT_MULTIPOINTM\n             || psShape->nSHPType == SHPT_MULTIPOINTZ )\n    {\n\tint32\t\tnPoints;\n\tint    \t\ti, nOffset;\n\n\tmemcpy( &nPoints, psSHP->pabyRec + 44, 4 );\n\tif( bBigEndian ) SwapWord( 4, &nPoints );\n\n\tpsShape->nVertices = nPoints;\n        psShape->padfX = (double *) calloc(nPoints,sizeof(double));\n        psShape->padfY = (double *) calloc(nPoints,sizeof(double));\n        psShape->padfZ = (double *) calloc(nPoints,sizeof(double));\n        psShape->padfM = (double *) calloc(nPoints,sizeof(double));\n\n\tfor( i = 0; i < nPoints; i++ )\n\t{\n\t    memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );\n\t    memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );\n\n\t    if( bBigEndian ) SwapWord( 8, psShape->padfX + i );\n\t    if( bBigEndian ) SwapWord( 8, psShape->padfY + i );\n\t}\n\n        nOffset = 48 + 16*nPoints;\n        \n/* -------------------------------------------------------------------- */\n/*\tGet the X/Y bounds.\t\t\t\t\t\t*/\n/* -------------------------------------------------------------------- */\n        memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 +  4, 8 );\n        memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );\n        memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );\n        memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );\n\n\tif( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );\n\tif( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );\n\tif( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );\n\tif( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );\n\n/* -------------------------------------------------------------------- */\n/*      If we have a Z coordinate, collect that now.                    */\n/* -------------------------------------------------------------------- */\n        if( psShape->nSHPType == SHPT_MULTIPOINTZ )\n        {\n            memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );\n            memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );\n            \n            if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );\n            if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );\n            \n            for( i = 0; i < nPoints; i++ )\n            {\n                memcpy( psShape->padfZ + i,\n                        psSHP->pabyRec + nOffset + 16 + i*8, 8 );\n                if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );\n            }\n\n            nOffset += 16 + 8*nPoints;\n        }\n\n/* -------------------------------------------------------------------- */\n/*      If we have a M measure value, then read it now.  We assume      */\n/*      that the measure can be present for any shape if the size is    */\n/*      big enough, but really it will only occur for the Z shapes      */\n/*      (options), and the M shapes.                                    */\n/* -------------------------------------------------------------------- */\n        if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )\n        {\n            memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );\n            memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );\n            \n            if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );\n            if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );\n            \n            for( i = 0; i < nPoints; i++ )\n            {\n                memcpy( psShape->padfM + i,\n                        psSHP->pabyRec + nOffset + 16 + i*8, 8 );\n                if( bBigEndian ) SwapWord( 8, psShape->padfM + i );\n            }\n        }\n    }\n\n/* ==================================================================== */\n/*      Extract vertices for a point.                                   */\n/* ==================================================================== */\n    else if( psShape->nSHPType == SHPT_POINT\n             || psShape->nSHPType == SHPT_POINTM\n             || psShape->nSHPType == SHPT_POINTZ )\n    {\n        int\tnOffset;\n        \n\tpsShape->nVertices = 1;\n        psShape->padfX = (double *) calloc(1,sizeof(double));\n        psShape->padfY = (double *) calloc(1,sizeof(double));\n        psShape->padfZ = (double *) calloc(1,sizeof(double));\n        psShape->padfM = (double *) calloc(1,sizeof(double));\n\n\tmemcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );\n\tmemcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );\n\n\tif( bBigEndian ) SwapWord( 8, psShape->padfX );\n\tif( bBigEndian ) SwapWord( 8, psShape->padfY );\n\n        nOffset = 20 + 8;\n        \n/* -------------------------------------------------------------------- */\n/*      If we have a Z coordinate, collect that now.                    */\n/* -------------------------------------------------------------------- */\n        if( psShape->nSHPType == SHPT_POINTZ )\n        {\n            memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );\n        \n            if( bBigEndian ) SwapWord( 8, psShape->padfZ );\n            \n            nOffset += 8;\n        }\n\n/* -------------------------------------------------------------------- */\n/*      If we have a M measure value, then read it now.  We assume      */\n/*      that the measure can be present for any shape if the size is    */\n/*      big enough, but really it will only occur for the Z shapes      */\n/*      (options), and the M shapes.                                    */\n/* -------------------------------------------------------------------- */\n        if( psSHP->panRecSize[hEntity]+8 >= nOffset + 8 )\n        {\n            memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );\n        \n            if( bBigEndian ) SwapWord( 8, psShape->padfM );\n        }\n\n/* -------------------------------------------------------------------- */\n/*      Since no extents are supplied in the record, we will apply      */\n/*      them from the single vertex.                                    */\n/* -------------------------------------------------------------------- */\n        psShape->dfXMin = psShape->dfXMax = psShape->padfX[0];\n        psShape->dfYMin = psShape->dfYMax = psShape->padfY[0];\n        psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0];\n        psShape->dfMMin = psShape->dfMMax = psShape->padfM[0];\n    }\n\n    return( psShape );\n}\n\n/************************************************************************/\n/*                            SHPTypeName()                             */\n/************************************************************************/\n\nconst char SHPAPI_CALL1(*)\nSHPTypeName( int nSHPType )\n\n{\n    switch( nSHPType )\n    {\n      case SHPT_NULL:\n        return \"NullShape\";\n\n      case SHPT_POINT:\n        return \"Point\";\n\n      case SHPT_ARC:\n        return \"Arc\";\n\n      case SHPT_POLYGON:\n        return \"Polygon\";\n\n      case SHPT_MULTIPOINT:\n        return \"MultiPoint\";\n        \n      case SHPT_POINTZ:\n        return \"PointZ\";\n\n      case SHPT_ARCZ:\n        return \"ArcZ\";\n\n      case SHPT_POLYGONZ:\n        return \"PolygonZ\";\n\n      case SHPT_MULTIPOINTZ:\n        return \"MultiPointZ\";\n        \n      case SHPT_POINTM:\n        return \"PointM\";\n\n      case SHPT_ARCM:\n        return \"ArcM\";\n\n      case SHPT_POLYGONM:\n        return \"PolygonM\";\n\n      case SHPT_MULTIPOINTM:\n        return \"MultiPointM\";\n\n      case SHPT_MULTIPATCH:\n        return \"MultiPatch\";\n\n      default:\n        return \"UnknownShapeType\";\n    }\n}\n\n/************************************************************************/\n/*                          SHPPartTypeName()                           */\n/************************************************************************/\n\nconst char SHPAPI_CALL1(*)\nSHPPartTypeName( int nPartType )\n\n{\n    switch( nPartType )\n    {\n      case SHPP_TRISTRIP:\n        return \"TriangleStrip\";\n        \n      case SHPP_TRIFAN:\n        return \"TriangleFan\";\n\n      case SHPP_OUTERRING:\n        return \"OuterRing\";\n\n      case SHPP_INNERRING:\n        return \"InnerRing\";\n\n      case SHPP_FIRSTRING:\n        return \"FirstRing\";\n\n      case SHPP_RING:\n        return \"Ring\";\n\n      default:\n        return \"UnknownPartType\";\n    }\n}\n\n/************************************************************************/\n/*                          SHPDestroyObject()                          */\n/************************************************************************/\n\nvoid SHPAPI_CALL\nSHPDestroyObject( SHPObject * psShape )\n\n{\n    if( psShape == NULL )\n        return;\n    \n    if( psShape->padfX != NULL )\n        free( psShape->padfX );\n    if( psShape->padfY != NULL )\n        free( psShape->padfY );\n    if( psShape->padfZ != NULL )\n        free( psShape->padfZ );\n    if( psShape->padfM != NULL )\n        free( psShape->padfM );\n\n    if( psShape->panPartStart != NULL )\n        free( psShape->panPartStart );\n    if( psShape->panPartType != NULL )\n        free( psShape->panPartType );\n\n    free( psShape );\n}\n\n/************************************************************************/\n/*                          SHPRewindObject()                           */\n/*                                                                      */\n/*      Reset the winding of polygon objects to adhere to the           */\n/*      specification.                                                  */\n/************************************************************************/\n\nint SHPAPI_CALL\nSHPRewindObject( SHPHandle hSHP, SHPObject * psObject )\n\n{\n    int  iOpRing, bAltered = 0;\n\n/* -------------------------------------------------------------------- */\n/*      Do nothing if this is not a polygon object.                     */\n/* -------------------------------------------------------------------- */\n    if( psObject->nSHPType != SHPT_POLYGON\n        && psObject->nSHPType != SHPT_POLYGONZ\n        && psObject->nSHPType != SHPT_POLYGONM )\n        return 0;\n\n    if( psObject->nVertices == 0 || psObject->nParts == 0 )\n        return 0;\n\n/* -------------------------------------------------------------------- */\n/*      Process each of the rings.                                      */\n/* -------------------------------------------------------------------- */\n    for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ )\n    {\n        int      bInner, iVert, nVertCount, nVertStart, iCheckRing;\n        double   dfSum, dfTestX, dfTestY;\n\n/* -------------------------------------------------------------------- */\n/*      Determine if this ring is an inner ring or an outer ring        */\n/*      relative to all the other rings.  For now we assume the         */\n/*      first ring is outer and all others are inner, but eventually    */\n/*      we need to fix this to handle multiple island polygons and      */\n/*      unordered sets of rings.                                        */\n/* -------------------------------------------------------------------- */\n        dfTestX = psObject->padfX[psObject->panPartStart[iOpRing]];\n        dfTestY = psObject->padfY[psObject->panPartStart[iOpRing]];\n\n        bInner = FALSE;\n        for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ )\n        {\n            int iEdge;\n\n            if( iCheckRing == iOpRing )\n                continue;\n            \n            nVertStart = psObject->panPartStart[iCheckRing];\n\n            if( iCheckRing == psObject->nParts-1 )\n                nVertCount = psObject->nVertices \n                    - psObject->panPartStart[iCheckRing];\n            else\n                nVertCount = psObject->panPartStart[iCheckRing+1] \n                    - psObject->panPartStart[iCheckRing];\n\n            for( iEdge = 0; iEdge < nVertCount; iEdge++ )\n            {\n                int iNext;\n\n                if( iEdge < nVertCount-1 )\n                    iNext = iEdge+1;\n                else\n                    iNext = 0;\n\n                if( (psObject->padfY[iEdge+nVertStart] < dfTestY \n                     && psObject->padfY[iNext+nVertStart] >= dfTestY)\n                    || (psObject->padfY[iNext+nVertStart] < dfTestY \n                        && psObject->padfY[iEdge+nVertStart] >= dfTestY) )\n                {\n                    if( psObject->padfX[iEdge+nVertStart] \n                        + (dfTestY - psObject->padfY[iEdge+nVertStart])\n                           / (psObject->padfY[iNext+nVertStart]\n                              - psObject->padfY[iEdge+nVertStart])\n                           * (psObject->padfX[iNext+nVertStart]\n                              - psObject->padfX[iEdge+nVertStart]) < dfTestX )\n                        bInner = !bInner;\n                }\n            }\n        }\n\n/* -------------------------------------------------------------------- */\n/*      Determine the current order of this ring so we will know if     */\n/*      it has to be reversed.                                          */\n/* -------------------------------------------------------------------- */\n        nVertStart = psObject->panPartStart[iOpRing];\n\n        if( iOpRing == psObject->nParts-1 )\n            nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];\n        else\n            nVertCount = psObject->panPartStart[iOpRing+1] \n                - psObject->panPartStart[iOpRing];\n\n        dfSum = 0.0;\n        for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ )\n        {\n            dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1]\n                - psObject->padfY[iVert] * psObject->padfX[iVert+1];\n        }\n\n        dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart]\n               - psObject->padfY[iVert] * psObject->padfX[nVertStart];\n\n/* -------------------------------------------------------------------- */\n/*      Reverse if necessary.                                           */\n/* -------------------------------------------------------------------- */\n        if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) )\n        {\n            int   i;\n\n            bAltered++;\n            for( i = 0; i < nVertCount/2; i++ )\n            {\n                double dfSaved;\n\n                /* Swap X */\n                dfSaved = psObject->padfX[nVertStart+i];\n                psObject->padfX[nVertStart+i] = \n                    psObject->padfX[nVertStart+nVertCount-i-1];\n                psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;\n\n                /* Swap Y */\n                dfSaved = psObject->padfY[nVertStart+i];\n                psObject->padfY[nVertStart+i] = \n                    psObject->padfY[nVertStart+nVertCount-i-1];\n                psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;\n\n                /* Swap Z */\n                if( psObject->padfZ )\n                {\n                    dfSaved = psObject->padfZ[nVertStart+i];\n                    psObject->padfZ[nVertStart+i] = \n                        psObject->padfZ[nVertStart+nVertCount-i-1];\n                    psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;\n                }\n\n                /* Swap M */\n                if( psObject->padfM )\n                {\n                    dfSaved = psObject->padfM[nVertStart+i];\n                    psObject->padfM[nVertStart+i] = \n                        psObject->padfM[nVertStart+nVertCount-i-1];\n                    psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;\n                }\n            }\n        }\n    }\n\n    return bAltered;\n}\n"
  },
  {
    "path": "test/address.rb",
    "content": "$LOAD_PATH.unshift '../lib'\n\nrequire 'test/unit'\nrequire 'set'\nrequire 'geocoder/us/address'\n\ninclude Geocoder::US\n\nclass TestAddress < Test::Unit::TestCase\n  def test_new\n    addr = Address.new(\"1600 Pennsylvania Av., Washington DC\")\n    assert_equal \"1600 Pennsylvania Av, Washington DC\", addr.text\n  end\n  def test_clean\n    fixtures = [\n      [ \"cleaned text\", \"cleaned: text!\" ],\n      [ \"cleaned-text 2\", \"cleaned-text: #2?\" ],\n      [ \"it's working 1/2\", \"~it's working 1/2~\" ],\n      [ \"it's working, yes\", \"it's working, yes...?\" ],\n      [ \"it's working & well\", \"it's working & well?\" ]\n    ]\n    fixtures.each {|output, given|\n      assert_equal output, Address.new(given).text\n    }\n  end\n  def test_expand_numbers\n    num_list = [\"5\", \"fifth\", \"five\"]\n    num_list.each {|n|\n      addr = Address.new(n)\n      assert_equal num_list, addr.expand_numbers(n).to_a.sort\n    }\n  end\n  def test_city_parse\n    places = [\n      [ \"New York, NY\",     \"New York\", \"NY\", \"\" ],\n      [ \"NY\",               \"\", \"NY\",   \"\" ],\n      [ \"New York\",         \"New York\", \"NY\",   \"\" ],\n      [ \"Philadelphia\",     \"Philadelphia\", \"\", \"\" ],\n      [ \"Philadelphia PA\",  \"Philadelphia\", \"PA\", \"\" ],\n      [ \"Philadelphia, PA\", \"Philadelphia\", \"PA\", \"\" ],\n      [ \"Philadelphia, Pennsylvania\", \"Philadelphia\", \"PA\", \"\" ],\n      [ \"Philadelphia, Pennsylvania 19131\", \"Philadelphia\", \"PA\", \"19131\" ],\n      [ \"Philadelphia 19131\", \"Philadelphia\", \"\", \"19131\" ],\n      [ \"Pennsylvania 19131\", \"Pennsylvania\", \"PA\", \"19131\" ], # kind of a misfeature\n      [ \"19131\", \"\", \"\", \"19131\" ],\n      [ \"19131-9999\", \"\", \"\", \"19131\" ],\n    ]\n    for fixture in places\n      addr  = Address.new fixture[0]\n      [:city, :state, :zip].zip(fixture[1..3]).each {|key,val|\n        result = addr.send key\n        result = [result.downcase] unless result.kind_of? Array\n        if result.empty?\n          assert_equal val, \"\", key.to_s + \" test no result \" + fixture.join(\"/\")\n        else\n          assert result.member?(val.downcase), key.to_s + \" test \" + result.inspect + fixture.join(\"/\")\n        end\n      }\n    end\n  end\n  \n  def test_po_box\n    addr_po = Address.new \"PO Box 1111 Herndon VA 20171\"\n    assert addr_po.po_box?, true \n  end\n  \n\n  \n  def test_parse\n    addrs = [\n      {:text   => \"1600 Pennsylvania Av., Washington DC 20050\",\n       :number => \"1600\",\n       :street => \"Pennsylvania Ave\",\n       :city   => \"Washington\",\n       :state  => \"DC\",\n       :zip    => \"20050\"},\n\n      {:text   => \"1600 Pennsylvania, Washington DC\",\n       :number => \"1600\",\n       :street => \"Pennsylvania\",\n       :city   => \"Washington\",\n       :state  => \"DC\"},\n\n      {:text   => \"1600 Pennsylvania Washington DC\",\n       :number => \"1600\",\n       :street => \"Pennsylvania Washington\",\n       :city   => \"Pennsylvania Washington\", # FIXME\n       :state  => \"DC\"},\n\n      {:text   => \"1600 Pennsylvania Washington\",\n       :number => \"1600\",\n       :street => \"Pennsylvania\",\n       :city   => \"Washington\",\n       :state  => \"WA\"}, # FIXME\n\n      {:text   => \"1600 Pennsylvania 20050\",\n       :number => \"1600\",\n       :street => \"Pennsylvania\", # FIXME\n       :zip    => \"20050\"},\n\n      {:text   => \"1600 Pennsylvania Av, 20050-9999\",\n       :number => \"1600\",\n       :street => \"Pennsylvania Ave\",\n       :zip    => \"20050\"},\n\n      {:text   => \"1005 Gravenstein Highway North, Sebastopol CA\",\n       :number => \"1005\",\n       :street => \"Gravenstein Hwy N\",\n       :city   => \"Sebastopol\",\n       :state  => \"CA\"},\n\n      {:text   => \"100 N 7th St, Brooklyn\",\n       :number => \"100\",\n       :street => \"N 7 St\",\n       :city   => \"Brooklyn\"},\n\n      {:text   => \"100 N Seventh St, Brooklyn\",\n       :number => \"100\",\n       :street => \"N 7 St\",\n       :city   => \"Brooklyn\"},\n\n      {:text   => \"100 Central Park West, New York, NY\",\n       :number => \"100\",\n       :street => \"Central Park W\",\n       :city   => \"New York\",\n       :state  => \"NY\"},\n\n      {:text   => \"100 Central Park West, 10010\",\n       :number => \"100\",\n       :street => \"Central Park W\",\n       :zip    => \"10010\"},\n\n      {:text   => \"1400 Avenue of the Americas, New York, NY 10019\",\n       :number => \"1400\",\n       :street => \"Ave of the Americas\",\n       :city   => \"New York\",\n       :state  => \"NY\"},\n\n      {:text   => \"1400 Avenue of the Americas, New York\",\n       :number => \"1400\",\n       :street => \"Ave of the Americas\",\n       :city   => \"New York\"},\n\n      {:text   => \"1400 Ave of the Americas, New York\",\n       :number => \"1400\",\n       :street => \"Ave of the Americas\",\n       :city   => \"New York\"},\n\n      {:text   => \"1400 Av of the Americas, New York\",\n       :number => \"1400\",\n       :street => \"Ave of the Americas\",\n       :city   => \"New York\"},\n\n      {:text   => \"1400 Av of the Americas New York\",\n       :number => \"1400\",\n       :street => \"Ave of the Americas\",\n       :city   => \"New York\"},\n\n    ]\n    for fixture in addrs\n      text = fixture.delete(:text)\n      addr = Address.new(text)\n      for key, val in fixture\n        result = addr.send key\n        if result.kind_of? Array\n          result.map! {|str| str.downcase}\n          assert result.member?(val.downcase), \"#{text} (#{key}) = #{result.inspect}\"\n        else\n          assert_equal val, result, \"#{text} (#{key}) = #{result.inspect}\"\n        end\n      end\n    end\n  end\n  \n  def test_skip_parse\n    addresses = [\n      {:street => \"1233 Main St\", :city => \"Springfield\", :region => \"VA\", :postal_code => \"12345\", :final_number => \"1233\", :parsed_street => \"main st\"},\n      {:street => \"somewhere Ln\", :city => \"Somewhere\", :region => \"WI\", :postal_code => \"22222\", :number => \"402\", :parsed_street => \"somewhere ln\", :final_number => \"402\"},\n      ]  \n      for preparsed_address in addresses\n        address_for_geocode = Address.new preparsed_address \n        assert_equal preparsed_address[:parsed_street],address_for_geocode.street[0]\n        assert_equal preparsed_address[:final_number],address_for_geocode.number\n        assert_equal preparsed_address[:city],address_for_geocode.city[0]\n        assert_equal preparsed_address[:region],address_for_geocode.state\n        assert_equal preparsed_address[:postal_code],address_for_geocode.zip\n      end\n  end\n  \n  def test_states_abbreviated_in_skip_parse\n    addresses = [\n      {:street => \"123 Main St\", :city => \"Springfield\", :region => \"Virginia\", :postal_code => \"12345\",:state_abbrev => \"VA\"},\n      {:street => \"402 Somewhere Ln\", :city => \"Somewhere\", :region => \"WI\", :postal_code => \"22222\", :state_abbrev => \"WI\"},\n      ]\n      for preparsed_address in addresses\n        address_for_geocode = Address.new preparsed_address \n        assert_equal preparsed_address[:state_abbrev],address_for_geocode.state\n      end\n    \n  end\n  \n  def test_address_hash\n    addresses = [\n      {:address => \"Herndon, VA\", :place_check => [\"herndon\"]},\n      {:address => \"Arlington, VA\", :place_check => [\"arlington\"]}\n      ]\n      for preparsed_address in addresses\n        address_for_geocode = Address.new preparsed_address \n        assert_equal preparsed_address[:place_check],address_for_geocode.city\n      end\n  end\n  \n  def test_partial_address\n    addresses = [\n      {:street => \"2200 Wilson Blvd\", :postal_code => \"22201\"},\n      ]\n      for preparsed_address in addresses\n        address_for_geocode = Address.new preparsed_address\n        assert_equal preparsed_address[:postal_code],address_for_geocode.zip\n      end\n    \n    \n  end\n  \n  def test_country_parse\n    addresses = [\n      {:city => \"Paris\", :country => \"FR\"},\n      ]\n      \n      for preparsed_address in addresses\n        address_for_geocode = Address.new preparsed_address\n        assert_equal preparsed_address[:country],address_for_geocode.state\n      end\n  end\n  \nend\n"
  },
  {
    "path": "test/benchmark.rb",
    "content": "#!/usr/bin/ruby\n\nrequire 'test/unit'\nrequire 'geocoder/us/database'\nrequire 'benchmark'\ninclude Benchmark          # we need the CAPTION and FMTSTR constants\n\ndb = Geocoder::US::Database.new(\"/mnt/tiger2008/geocoder.db\")\n\nn = 50\ns = \"1005 Gravenstein Hwy N, Sebastopol CA 95472\"\na = Geocoder::US::Address.new(s)\n\nprint db.geocode(s)\n\nBenchmark.bmbm do |x|\n  x.report(\"parse max_penalty=0\") { n.times{a.parse(0)} }\n  x.report(\"parse max_penalty=1\") { n.times{a.parse(1)} }\n  x.report(\"geocode\") { n.times{db.geocode(s)} }\nend\n"
  },
  {
    "path": "test/constants.rb",
    "content": "$LOAD_PATH.unshift '../lib'\n\nrequire 'test/unit'\nrequire 'geocoder/us/constants'\n\ninclude Geocoder::US\n\nclass TestConstants < Test::Unit::TestCase\n  def initialize (*args)\n    @map = Map[\n      \"Abbreviation\" => \"abbr\",\n      \"Two words\"    => \"2words\",\n      \"Some three words\" => \"3words\"\n    ]\n    super(*args)\n  end\n  def test_class_constructor\n    assert_kind_of Map, @map\n    assert_kind_of Hash, @map\n  end  \n  def test_key\n    assert @map.key?( \"Abbreviation\" )\n    assert @map.key?( \"abbreviation\" )\n    assert !(@map.key? \"abbreviation?\")\n    assert @map.key?( \"abbr\" )\n    assert @map.key?( \"Two words\" )\n    assert @map.key?( \"2words\" )\n  end\n  def test_fetch\n    assert_equal \"abbr\", @map[\"Abbreviation\"]\n    assert_equal \"abbr\", @map[\"abbreviation\"]\n    assert_nil @map[\"abbreviation?\"]\n    assert_equal \"abbr\", @map[\"abbr\"]\n    assert_equal \"2words\", @map[\"Two words\"]\n    assert_equal \"2words\", @map[\"2words\"]\n  end\n#  def test_partial\n#    assert @map.partial?( \"Abbreviation\" )\n#    assert @map.partial?( \"Two\" )\n#    assert @map.partial?( \"two\" )\n#    assert !(@map.partial? \"words\")\n#    assert @map.partial?( \"Some\" )\n#    assert !(@map.partial? \"words\")\n#    assert @map.partial?( \"Some three\" )\n#    assert @map.partial?( \"SOME THREE WORDS\" )\n#  end\n  def test_constants\n    assert_kind_of Map, Directional\n    assert_kind_of Map, Prefix_Qualifier\n    assert_kind_of Map, Suffix_Qualifier\n    assert_kind_of Map, Prefix_Type\n    assert_kind_of Map, Suffix_Type\n    assert_kind_of Map, Unit_Type\n    assert_kind_of Map, Name_Abbr\n    assert_kind_of Map, State\n  end\nend\n"
  },
  {
    "path": "test/data/address-sample.csv",
    "content": "address,number,predir,prequal,pretyp,street,suftyp,sufqual,sufdir,unittyp,unit,city,state,zip,lon,lat,count,comment\n\"93 NORTH 9TH STREET, BROOKLYN NY 11211\",93,N,,,9th,St,,,,,Brooklyn,NY,11211,,,,\n\"380 WESTMINSTER ST, PROVIDENCE RI 02903\",380,,,,Westminster,St,,,,,Providence,RI,02903,,,,\n\"177 MAIN STREET, LITTLETON NH 03561\",177,,,,Main,St,,,,,Littleton,NH,03561,,,,\n\"202 HARLOW ST, BANGOR ME 04401\",202,,,,Harlow,St,,,,,Bangor,ME,04401,,,,\n\"46 FRONT STREET, WATERVILLE, ME 04901\",46,,,,Front,St,,,,,Waterville,ME,04901,,,,\n\"22 SUSSEX ST, HACKENSACK NJ 07601\",22,,,,Sussex,St,,,,,Hackensack,NJ,07601,,,,\n\"75 OAK STREET, PATCHOGUE NY 11772\",75,,,,Oak,St,,,,,Patchogue,NY,11772,,,,\n\"1 CLINTON AVE, ALBANY NY 12207\",1,,,,Clinton,Ave,,,,,Albany,NY,12207,,,,\n\"7242 ROUTE 9, PLATTSBURGH NY 12901\",7242,,,US Hwy,9,,,,,,Plattsburgh,NY,12901,,,,\n\"520 5TH AVE, MCKEESPORT PA 15132\",520,,,,5th,Ave,,,,,McKeesport,PA,15132,,,,\n\"122 W 3RD STREET, GREENSBURG PA 15601\",122,W,,,3rd,St,,,,,Greensburg,PA,15601,,,,\n\"901 UNIVERSITY DR, STATE COLLEGE PA 16801\",901,,,,University,Dr,,,,,\"State College\",PA,16801,,,,\n\"240 W 3RD ST, WILLIAMSPORT PA 17701\",240,W,,,3rd,St,,,,,Williamsport,PA,17701,,,,\n\"41 N 4TH ST, ALLENTOWN PA 18102\",41,N,,,4th,St,,,,,Allentown,PA,18102,,,,\n\"2221 W. MARKET STREET, POTTSVILLE PA 17901\",2221,W,,,Market,St,,,,,Pottsville,PA,17901,,,,\n\"337 BRIGHTSEAT ROAD, LANDOVER MD 20785\",337,,,,Brightseat,Rd,,,,,Hyattsville,MD,20785,,,,\"canonical place\"\n\"101 CHESAPEAKE BLVD, ELKTON MD 21921\",103,,,,Chesapeake,Blvd,,,,,Elkton,MD,21921,,,,\"find nearest corner\"\n\"2875 SABRE ST, VIRGINIA BEACH VA 23452\",2809,,,,Sabre,St,,,,,\"Virginia Beach\",VA,23452,,,,\"find nearest corner\"\n\"324 COMMERCE ROAD, FARMVILLE VA 23901\",324,,,,Commerce,St,,,,,Clarksville,VA,23927,,,,\"nearby address; might be TIGER omission\"\n\"1480 EAST MAIN STREET, WYTHEVILLE VA 24382\",1480,W,,,Main,St,,,,,Wytheville,VA,24382,,,,\"nearby address; TIGER omission\"\n\"116 N JEFFERSON STREET, ROANOKE VA 24016\",116,N,,,Jefferson,St,,,,,Roanoke,VA,24016,,,,\n\"50 MCDOWELL STREET, WELCH WV 24801\",50,,,,\"Mc Dowell\",St,,,,,Welch,WV,24801,,,,\n\"146 EAST FIRST AVE, WILLIAMSON WV 25661\",200,E,,,1st,Ave,,,,,Williamson,WV,25661,,,,\"find nearest corner\"\n\"1925 E MAIN ST, ALBEMARLE NC 28001\",1925,E,,,Main,St,,,,,Albemarle,NC,28001,,,,\n\"1013 SPRING LANE, SANFORD NC 27330\",1013,,,,Spring,Ln,,,,,Sanford,NC,27330,,,,\n\"145 ROWAN STREET, FAYETTEVILLE NC 28301\",145,,,,Rowan,St,,,,,Fayetteville,NC,28301,,,,\n\"1420 MCCARTHY BLVD, NEW BERN NC 28562\",1420,,,,McCarthy,Blvd,,,,,\"New Bern\",NC,28562,,,,\n\"115 ENTERPRISE COURT, GREENWOOD SC 29649\",115,,,,Enterprise,Ct,,,,,Greenwood,SC,29649,,,,\n\"732 W 2ND ST, TIFTON GA 31794\",732,,,,2nd,St,,W,,,Tifton,GA,31793,,,,\"TIGER artifact\"\n\"97 WEST OAK AVE, PANAMA CITY FL 32401\",97,,,,Oak,Ave,,,,,\"Panama City\",FL,32401,,,,\"predir is TIGER artifact\"\n\"2276 WILTON DR, WILTON MANORS FL 33305\",2276,,,,Wilton,Dr,,,,,\"Fort Lauderdale\",FL,33305,,,,\"canonical place\"\n\"203 SOUTH WALNUT ST, FLORENCE AL 35630\",203,S,,,Walnut,St,,,,,Florence,AL,35630,,,,\n\"108 CENTER POINTE DR, CLARKSVILLE TN 37040\",108,,,,\"Center Pointe\",Dr,,,,,Clarksville,TN,37040,,,,\n\"1800 OLD TROY RD, UNION CITY TN 38261\",1800,,Old,,Troy,Rd,,,,,\"Union City\",TN,38261,,,,\n\"931 OLD SMITHVILLE HWY, MCMINNVILLE TN 37110\",931,,Old,,Smithville,Rd,,,,,McMinnville,TN,37110,,,,\n\"1301 GREENE STREET, MARIETTA OH 45750\",1301,,,,Greene,St,,,,,Marietta,OH,45750,,,,\n\"602 SOUTH MICHIGAN ST, SOUTH BEND IN 46601\",602,S,,,Michigan,St,,,,,\"South Bend\",IN,46601,,,,\n\"500 NORTH A STREET, RICHMOND IN 47374\",500,N,,,A,St,,,,,Richmond,IN,47374,,,,\n\"317 SOUTH DRAKE ROAD, KALAMAZOO MI 49009\",317,S,,,Drake,Rd,,,,,Kalamazoo,MI,49009,,,,\n\"105 Amity Way, Wayne PA 19087\",105,,,,Amity,Dr,,,,,Wayne,PA,19087,,,,\n\"305 W 45th St, New York NY 10036\",305,W,,,45,St,,,,,\"New York\",NY,10036,,,,\n\"11839 Federalist Way, Fairfax VA 22030\",11839,,,,Federalist,Way,,,,,Fairfax,VA,22030,,,,\n\"400 Monroe St, Hoboken, NJ 07030\",400,,,,Monroe,St,,,,,Hoboken,NJ,07030,,,,\n\"101 West End Avenue, New York NY 10023\",101,W,,,End,Ave,,,,,\"New York\",NY,10023,,,,\"predir is TIGER artifact\"\n\"2900 4TH AVE, BILLINGS MT 59101\",2900,,,,4th,Ave,,N,,,Billings,MT,59101,,,,\"returns 2 results\"\n\"158 N SCOTT STREET, JOLIET IL 60432\",158,N,,,Scott,St,,,,,Joliet,IL,60432,,,,\n\"1207 NETWORK CENTRE DR, EFFINGHAM IL 62401\",1207,,,,\"Network Centre\",Dr,,,,,Effingham,IL,62401,,,,\n\"3555 SOUTHERN HILLS DR, SIOUX CITY IA 51106\",3555,,,,\"Southern Hills\",Dr,,,,,\"Sioux City\",IA,51106,,,,\n\"300 E 3RD ST, NORTH PLATTE NE 69101\",300,E,,,3rd,St,,,,,\"North Platte\",NE,69101,,,,\n\"115 N WEBB RD, GRAND ISLAND NE 68803\",115,N,,,Webb,Rd,,,,,\"Grand Island\",NE,68803,,,,\n\"415 VALLEY VIEW DR, SCOTTSBLUFF NE 69361\",501,,,,\"Valley View\",Dr,,,,,\"Scottsbluff\",NE,69361,,,,\"find nearest corner\"\n"
  },
  {
    "path": "test/data/db-test.csv",
    "content": "address,number,street,city,state,zip,lon,lat,count,comment\n\"93 NORTH 9TH STREET, BROOKLYN NY 11211\",93,N 9th St,Brooklyn,NY,11211,-73.958096,40.720064,1,\n\"380 WESTMINSTER ST, PROVIDENCE RI 02903\",380,Westminster St,Providence,RI,02903,-71.415171,41.821004,1,\n\"177 MAIN STREET, LITTLETON NH 03561\",177,Main St,Littleton,NH,03561,-71.776393,44.307299,1,range\n\"202 HARLOW ST, BANGOR ME 04401\",202,Harlow St,Bangor,ME,04401,-68.773934,44.805202,1,\n\"46 FRONT STREET, WATERVILLE, ME 04901\",46,Front St,Waterville,ME,04901,-69.628598,44.550988,1,\n\"22 SUSSEX ST, HACKENSACK NJ 07601\",22,Sussex St,Hackensack,NJ,07601,-74.04821,40.880328,1,\n\"75 OAK STREET, PATCHOGUE NY 11772\",75,Oak St,Patchogue,NY,11772,-73.01036,40.768522,1,\n\"1 CLINTON AVE, ALBANY NY 12207\",1,Clinton Ave,Albany,NY,12207,-73.750031,42.654244,1,\n\"7242 ROUTE 9, PLATTSBURGH NY 12901\",7242,US Hwy 9,Plattsburgh,NY,12901,-73.428066,44.735338,1,\n\"520 5TH AVE, MCKEESPORT PA 15132\",520,5th Ave,McKeesport,PA,15132,-79.861023,40.351228,1,\n\"122 W 3RD STREET, GREENSBURG PA 15601\",122,W 3rd St,Greensburg,PA,15601,-79.546244,40.299681,1,\n\"901 UNIVERSITY DR, STATE COLLEGE PA 16801\",901,University Dr,State College,PA,16801,-77.844056,40.797191,1,\n\"240 W 3RD ST, WILLIAMSPORT PA 17701\",240,W 3rd St,Williamsport,PA,17701,-77.005601,41.238969,1,\n\"41 N 4TH ST, ALLENTOWN PA 18102\",41,N 4th St,Allentown,PA,18102,-75.466113,40.605368,1,\n\"2221 W. MARKET STREET, POTTSVILLE PA 17901\",2221,W Market St,Pottsville,PA,17901,-76.226401,40.674702,1,\n\"337 BRIGHTSEAT ROAD, LANDOVER MD 20785\",337,Brightseat Rd,Hyattsville,MD,20785,-76.850995,38.892762,1,canonical place\n\"101 CHESAPEAKE BLVD, ELKTON MD 21921\",109,Chesapeake Blvd,Elkton,MD,21921,-75.786853,39.6045,1,find nearest corner\n\"2875 SABRE ST, VIRGINIA BEACH VA 23452\",2809,Sabre St,Virginia Beach,VA,23452,-76.067835,36.822959,1,find nearest corner\n\"324 COMMERCE ROAD, FARMVILLE VA 23901\",324,Commerce Rd,Farmville,VA,23901,-78.423296,37.273311,1,fixed in TIGER 2010\n\"1480 EAST MAIN STREET, WYTHEVILLE VA 24382\",1168,E Main St,Wytheville,VA,24382,-81.069279,36.951346,1,nearby address; TIGER omission\n\"116 N JEFFERSON STREET, ROANOKE VA 24016\",116,N Jefferson St,Roanoke,VA,24016,-79.940537,37.275163,1,\n\"50 MCDOWELL STREET, WELCH WV 24801\",50,Mc Dowell St,Welch,WV,24801,-81.585586,37.433465,1,\n\"146 EAST FIRST AVE, WILLIAMSON WV 25661\",200,E 1st Ave,Williamson,WV,25661,-82.277886,37.670798,1,find nearest corner\n\"1925 E MAIN ST, ALBEMARLE NC 28001\",1925,E Main St,Albemarle,NC,28001,-80.163859,35.348818,1,\n\"1013 SPRING LANE, SANFORD NC 27330\",1013,Spring Ln,Sanford,NC,27330,-79.198776,35.487444,1,\n\"145 ROWAN STREET, FAYETTEVILLE NC 28301\",145,Rowan St,Fayetteville,NC,28301,-78.878696,35.057767,1,\n\"1420 MCCARTHY BLVD, NEW BERN NC 28562\",1399,McCarthy Blvd,New Bern,NC,28562,-77.094901,35.097183,1,broken in TIGER 2010\n\"115 ENTERPRISE COURT, GREENWOOD SC 29649\",115,Enterprise Ct,Greenwood,SC,29649,-82.164828,34.216732,1,\n\"732 W 2ND ST, TIFTON GA 31794\",732,W 2nd St,Tifton,GA,31794,-83.523812,31.457889,1,ZIP was fixed in TIGER 2010\n\"97 WEST OAK AVE, PANAMA CITY FL 32401\",95,W Oak Ave,Panama City,FL,32401,-85.661436,30.154306,1,broken in TIGER 2010\n\"2276 WILTON DR, WILTON MANORS FL 33305\",2276,Wilton Dr,Fort Lauderdale,FL,33305,-80.137273,26.156993,1,canonical place\n\"203 SOUTH WALNUT ST, FLORENCE AL 35630\",203,S Walnut St,Florence,AL,35630,-87.670768,34.800112,1,\n\"108 CENTER POINTE DR, CLARKSVILLE TN 37040\",108,Center Pointe Dr,Clarksville,TN,37040,-87.30888,36.56967,1,\n\"1800 OLD TROY RD, UNION CITY TN 38261\",1800,Old Troy Rd,Union City,TN,38261,-89.083201,36.416592,1,\n\"931 OLD SMITHVILLE HWY, MCMINNVILLE TN 37110\",931,Old Smithville Rd,McMinnville,TN,37110,-85.788518,35.701731,1,\n\"1301 GREENE STREET, MARIETTA OH 45750\",1301,Greene St,Marietta,OH,45750,-81.424821,39.426052,1,\n\"602 SOUTH MICHIGAN ST, SOUTH BEND IN 46601\",598,S Michigan St,South Bend,IN,46601,-86.25025,41.670964,1,broken in TIGER 2010\n\"500 NORTH A STREET, RICHMOND IN 47374\",500,N A St,Richmond,IN,47374,-84.89517,39.830625,1,\n\"317 SOUTH DRAKE ROAD, KALAMAZOO MI 49009\",317,S Drake Rd,Kalamazoo,MI,49009,-85.648132,42.288772,1,\n\"105 Amity Way, Wayne PA 19087\",105,Amity Dr,Wayne,PA,19087,-75.455425,40.076446,1,\n\"305 W 45th St, New York NY 10036\",305,W 45 St,New York,NY,10036,-73.991106,40.760371,1,\n\"11839 Federalist Way, Fairfax VA 22030\",11839,Federalist Way,Fairfax,VA,22030,-77.353695,38.849858,1,\n\"400 Monroe St, Hoboken, NJ 07030\",400,Monroe St,Hoboken,NJ,07030,-74.038654,40.743789,1,\n\"101 West End Avenue, New York NY 10023\",101,W End Ave,New York,NY,10023,-73.987822,40.775325,1,predir is TIGER artifact\n\"2900 4TH AVE, BILLINGS MT 59101\",2900,4th Ave N,Billings,MT,59101,-108.51073,45.783452,2,returns 2 results\n\"158 N SCOTT STREET, JOLIET IL 60432\",158,N Scott St,Joliet,IL,60432,-88.080083,41.526353,1,\n\"1207 NETWORK CENTRE DR, EFFINGHAM IL 62401\",1207,Network Centre Dr,Effingham,IL,62401,-88.526702,39.143248,1,\n\"3555 SOUTHERN HILLS DR, SIOUX CITY IA 51106\",3555,Southern Hills Dr,Sioux City,IA,51106,-96.353014,42.449259,1,\n\"300 E 3RD ST, NORTH PLATTE NE 69101\",300,E 3rd St,North Platte,NE,69101,-100.761028,41.135235,1,\n\"115 N WEBB RD, GRAND ISLAND NE 68803\",115,N Webb Rd,Grand Island,NE,68803,-98.378361,40.917627,1,\n\"415 VALLEY VIEW DR, SCOTTSBLUFF NE 69361\",501,Valley View Dr,Scottsbluff,NE,69361,-103.656078,41.879011,1,find nearest corner\n\"4018 W Ustick Rd, Meridian ID\",4018,W Ustick Rd,Meridian,ID,83646,-116.443792,43.634096,1,fixed in TIGER 2010\n\"2518 S Pacific Hwy, Medford OR\",2518,S Pacific Hwy,Medford,OR,97501,-122.855426,42.307241,1,fixed in TIGER 2010\n\"1111 River Rd Apt A17, Edgewater NJ 07020\",1111,River Rd,Edgewater,NJ,07020,-73.972261,40.830852,1,FIXME: parsing\n\"460 West St, Amherst MA 01002-2964\",460,West St,Amherst,MA,01002,-72.520228,42.34014,1,address is all abbreviations\n\"23 2nd St, Brooklyn NY\",23,2nd St,Brooklyn,NY,11231,-73.993897,40.67895,1,regression caused it to point to East Otto\n\"23 2nd St, Brooklyn, New York\",23,2nd St,Brooklyn,NY,11231,-73.993897,40.67895,1,regression caused it to point to Manhattan\n\"100 Central Park W, 10023\",100,Central Park W,New York,NY,10023,-73.975461,40.776899,1,the usual Central Park West parsing issues\n\"100 Central Park W, New York\",100,Central Park W,New York,NY,10023,-73.975461,40.776899,1,the usual Central Park West parsing issues\n"
  },
  {
    "path": "test/data/locations.csv",
    "content": "name,address\n\"Home\",\"2026 21st St. N, Arlington, VA 22201\"\n\"Work\",\"2200 Wilson Blvd., Arlington, VA 22201\"\n\"RTI\",\"1506 N Main St., Royal Oak, MI 48067\""
  },
  {
    "path": "test/database.rb",
    "content": "$LOAD_PATH.unshift '../lib'\n\nrequire 'test/unit'\nrequire 'geocoder/us/database'\nrequire 'csv'\n\nBase = File.dirname(__FILE__)\nDebug = false\n\nmodule Geocoder::US\n  Database_File = (\n    (ARGV[0] and !ARGV[0].empty?) ? ARGV[0] : \"../geocoderdata/geocoder.db\")\nend\n\nclass TestDatabase < Test::Unit::TestCase\n  def get_db\n    Geocoder::US::Database.new(Geocoder::US::Database_File, {:debug => Debug})\n  end\n  \n  # def get_international_db\n  #   Geocoder::US::Database.new(\"/Users/katechapman/Desktop/geonames1.db\", {:debug => true})\n  # end\n  \n  def setup\n    @db = get_db\n    #@db_intl = get_international_db\n    #assert_not_nil @db_intl\n    assert_not_nil @db\n  end\n  \n  def test_load\n    return if @db.nil?\n    assert_kind_of Geocoder::US::Database, @db \n  end\n  \n  def test_zip\n      return if @db.nil?\n      [ {:city=>\"Chicago\", :zip=>\"60601\", :state=>\"IL\", :precision=>:zip,\n         :fips_county=>\"17031\", :lon=>-87.622130,:lat=>41.885310, :score => 0.714},\n        {:city=>\"Philadelphia\", :zip=>\"19019\", :state=>\"PA\", :precision=>:zip,\n         :fips_county=>\"42101\", :lon=>-75.11787, :lat=>40.001811, :score => 0.714}\n      ].each {|record|\n        result = @db.geocode(record[:zip])\n        assert_equal result.length, 1\n        record.keys.each {|key| assert_equal record[key], result[0][key]}\n      }\n     \n    end\n    \n    # def test_international_place\n    #  return if @db_intl.nil?  \n    #  [ {:city=>\"Paris\", :state=>\"FR\"},\n    #    {:city=>\"Paris\", :state=>\"FR\"}\n    #  ].each {|record|\n    #    result = @db_intl.geocode(record)\n    #    assert_equal result.length, 1\n    #    record.keys.each {|key| assert_equal record[key], result[0][key]}\n    #  }\n    # end\n      \n          def test_place\n            return if @db.nil?\n            [ {:city=>\"Chicago\", :state=>\"IL\", :precision=>:city, :fips_county=>\"17031\", :score => 0.857},\n              {:city=>\"Philadelphia\", :state=>\"PA\", :precision=>:city, :fips_county=>\"42101\", :score => 0.857}\n            ].each {|record|\n              result = @db.geocode(record[:city] + \", \" + record[:state])\n              assert_equal result.length, 1\n              record.keys.each {|key| assert_equal record[key], result[0][key]}\n            }\n          \n          end\n        \n        # def test_international_place\n        #  return if @db_intl.nil?  \n        #    [ {:city=>\"Kabul\", :state=>\"AF\", :precision=>:city},\n        #      {:city=>\"Paris\", :state=>\"FR\", :precision=>:city}\n        #    ].each {|record|\n        #      result = @db_intl.geocode({:city => record[:city] , :state => record[:state]})  \n        #      puts result\n        #      assert_equal result.length, 1\n        #      record.keys.each {|key| assert_equal record[key], result[0][key]}\n        #    }\n        # end\n        \n\n         def test_sample\n           return if @db.nil?\n           # This test won't run properly on 1.8.7 or lower (?) - APS\n           return if RUBY_VERSION.split(\".\")[1] <= '8'\n           CSV.foreach(Base + \"/data/db-test.csv\", {:headers=>true}) do |row|\n             result = @db.geocode(row[0], true)\n             result[0][:count] = result.map{|a|[a[:lat], a[:lon]]}.to_set.length\n             fields = row.headers - [\"comment\", \"address\"]\n             fields.each {|f|\n               sample = row[f] || \"\"\n               given  = result[0][f.to_sym] || \"\"\n               sample = sample.to_f if given.kind_of? Float or given.kind_of? Fixnum\n               assert_equal sample, given, \"row: #{row.inspect}\\nfield: #{f.inspect} sample: #{sample.inspect}, given: #{given.inspect}\"\n        \n             }\n           end\n         end\n\n         def test_city_with_street_type_in_name\n           result = @db.geocode(\"Mountain View, CA\")\n           assert_equal result.length, 1\n           assert_equal result[0][:city], \"Mountain View\" # (and not \"Mountain View Acres, CA\")\n           assert_equal result[0][:state], \"CA\"\n         end\n         \n         def test_should_get_street_number_correctly\n           result = @db.geocode(\"460 West St, Amherst MA 01002-2964\", true)\n           assert_equal '460', result[0][:number] \n         end\n         \n         def test_should_geocode_with_hash\n           result = @db.geocode({:street => \"2200 Wilson Blvd\", :city => \"Arlington\", :region => \"VA\", :postal_code => \"22201\"}, true)\n           result2 = @db.geocode(\"2200 Wilson Blvd, Arlington, VA 22201\")\n           assert_equal result2,result\n         end\n         \n         def test_should_work_with_partial_hash\n           result = @db.geocode({:street => \"2200 Wilson Blvd\", :postal_code => \"22201\"})\n           assert_equal result[0][:precision],:range\n         end\n         \n         def test_weird_edge_case_explosion\n           result = @db.geocode({:street => \"1410 Spring Hill Rd\", :postal_code => \"20221\"})\n           result1 = @db.geocode(:street => \"402 Valley View Ave\", :postal_code => \"12345\")\n           assert_equal result[0][:precision],:zip    \n         end\n         \n         def test_city_state_together\n           result = @db.geocode({:city => \"Richmond\", :state => \"IN\"})  \n           assert_equal result[0][:precision],:city\n         end\n         \n         def test_state_street_together\n           result = @db.geocode({:region => \"VA\", :street => \"14333 Lee Jackson Memorial Hwy\"})  \n           #assert_equal result[0][:precision],:range\n         end\n        \n         def test_intersection\n          result = @db.geocode(\"Decatur St and Bryant St, San Francisco, CA 94103\")\n          assert_equal result[0][:precision], :intersection\n         end\n        \nend\n"
  },
  {
    "path": "test/generate.rb",
    "content": "#!/usr/bin/ruby\n\nrequire 'test/unit'\nrequire 'geocoder/us/database'\nrequire 'fastercsv'\n\ndb = Geocoder::US::Database.new(\"/mnt/tiger2008/geocoder.db\",\n                                \"/home/sderle/geocoder/lib/libsqlite3_geocoder.so\")\n\nif ARGV.length == 1\n  result = db.geocode(ARGV[0], 0, 50)\n  p result\nelse\n  FasterCSV.open(ARGV[1], \"w\", {:headers => true, :write_headers => true}) do |output|\n    FasterCSV.foreach(ARGV[0], {:headers => true}) do |row|\n      result = db.geocode(row[0])\n      count  = result.map{|a|[a[:lat], a[:lon]]}.to_set.length\n      if !result.empty?\n        row.headers[1..13].each_with_index {|f,i|\n          if result[0][f.to_sym] != row[i+1]\n            print \"#{row[0]} !#{f} -> #{result[0][f]} != #{row[i+1]}\\n\"\n          end\n        }\n        result[0][:count] = count\n        result[0][:address] = row[0]\n        result[0][:comment] = row[-1]\n        columns = row.headers.map{|col|col.to_sym}\n        output << result[0].values_at(*columns)\n      else\n        print \"!!! #{row[0]}\\n\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "test/numbers.rb",
    "content": "$LOAD_PATH.unshift '../lib'\n\nrequire 'test/unit'\nrequire 'geocoder/us/numbers'\n\ninclude Geocoder::US\n\nclass TestAddress < Test::Unit::TestCase\n  def test_number_to_cardinal\n    assert_equal 'one', Cardinals[1]\n    assert_equal 'ten', Cardinals[10] \n    assert_equal 'twelve', Cardinals[12] \n    assert_equal 'eighty-seven', Cardinals[87]\n  end\n\n  def test_cardinal_to_number\n    assert_equal 1,   Cardinals['one'] \n    assert_equal 1,   Cardinals['One']\n    assert_equal 10,  Cardinals['ten']\n    assert_equal 12,  Cardinals['twelve']\n    assert_equal 87,  Cardinals['eighty-seven']\n    assert_equal 87,  Cardinals['eighty seven']\n    assert_equal 87,  Cardinals['eightyseven']\n  end\n\n  def test_number_to_ordinal\n    assert_equal 'first', Ordinals[1]\n    assert_equal 'second', Ordinals[2]\n    assert_equal 'tenth', Ordinals[10] \n    assert_equal 'twelfth', Ordinals[12] \n    assert_equal 'twentieth', Ordinals[20]\n    assert_equal 'twenty-second', Ordinals[22]\n    assert_equal 'eighty-seventh', Ordinals[87]\n  end\n\n  def test_ordinal_to_number\n    assert_equal 1,   Ordinals['first'] \n    assert_equal 1,   Ordinals['First']\n    assert_equal 10,  Ordinals['tenth']\n    assert_equal 12,  Ordinals['twelfth']\n    assert_equal 73,  Ordinals['seventy-third']\n    assert_equal 74,  Ordinals['seventy  fourth']\n    assert_equal 75,  Ordinals['seventyfifth']\n    assert_equal nil, Ordinals['seventy-eleventh']\n  end\nend\n"
  },
  {
    "path": "test/run.rb",
    "content": "#!/usr/bin/ruby \n\n$LOAD_PATH << File.dirname(__FILE__)\n$LOAD_PATH << File.dirname(__FILE__) + \"/../lib\"\nputs \"Loadpath=#{$LOAD_PATH.inspect}\"\nrequire 'test/unit'\nrequire 'numbers'\nrequire 'constants'\nrequire 'address'\nrequire 'database'\n\n"
  }
]