[GRASS-SVN] r55582 - grass/trunk/lib/vector/Vlib

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Apr 1 08:15:14 PDT 2013


Author: martinl
Date: 2013-04-01 08:15:14 -0700 (Mon, 01 Apr 2013)
New Revision: 55582

Modified:
   grass/trunk/lib/vector/Vlib/bridges.c
   grass/trunk/lib/vector/Vlib/local_proto.h
   grass/trunk/lib/vector/Vlib/open.c
   grass/trunk/lib/vector/Vlib/read.c
   grass/trunk/lib/vector/Vlib/read_nat.c
   grass/trunk/lib/vector/Vlib/read_sfa.c
   grass/trunk/lib/vector/Vlib/write.c
   grass/trunk/lib/vector/Vlib/write_nat.c
   grass/trunk/lib/vector/Vlib/write_sfa.c
Log:
vlib: add V2__delete_line_topo_nat() 
      update V2__add_line_topo_nat()
      add extra checks (invalid line id) + update doxygen (note required build level)
      various minor issue


Modified: grass/trunk/lib/vector/Vlib/bridges.c
===================================================================
--- grass/trunk/lib/vector/Vlib/bridges.c	2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/bridges.c	2013-04-01 15:15:14 UTC (rev 55582)
@@ -28,9 +28,8 @@
     return (*ai < *bi ? -1 : (*ai > *bi));
 }
 
-static void
-remove_bridges(struct Map_info *Map, int chtype, struct Map_info *Err, 
-               int *lrm, int *brm);
+static void remove_bridges(struct Map_info *Map, int chtype, struct Map_info *Err, 
+                           int *lrm, int *brm);
 
 /*!
    \brief Remove bridges from vector map.
@@ -45,12 +44,9 @@
    \param Err vector map where deleted bridges are written or NULL
    \param lines_removed number of lines removed
    \param bridges_removed Err number of bridges removed
-
-   \return
- */
-void
-Vect_remove_bridges(struct Map_info *Map, struct Map_info *Err,
-                    int *lines_removed, int *bridges_removed)
+*/
+void Vect_remove_bridges(struct Map_info *Map, struct Map_info *Err,
+                         int *lines_removed, int *bridges_removed)
 {
     remove_bridges(Map, 0, Err, lines_removed, bridges_removed);
 }
@@ -69,12 +65,8 @@
    \param Err vector map where changed bridges are written or NULL
    \param lines_changed number of lines changed
    \param bridges_changed Err number of bridges changed
-
-   \return
- */
-
-void
-Vect_chtype_bridges(struct Map_info *Map, struct Map_info *Err,
+*/
+void Vect_chtype_bridges(struct Map_info *Map, struct Map_info *Err,
                     int *lines_changed, int *bridges_changed)
 {
     remove_bridges(Map, 1, Err, lines_changed, bridges_changed);
@@ -93,11 +85,10 @@
 
    List of all lines in chain is created during the cycle.
  */
-void
-remove_bridges(struct Map_info *Map, int chtype, struct Map_info *Err,
-               int *lrm, int *brm)
+void remove_bridges(struct Map_info *Map, int chtype, struct Map_info *Err,
+                    int *lrm, int *brm)
 {
-    int i, type, nlines, line, *bline;
+    int type, nlines, line, *bline;
     int left, right, node1, node2, current_line, next_line, abs_line;
     int bridges_removed = 0;	/* number of removed bridges */
     int lines_removed = 0;	/* number of lines removed */
@@ -219,6 +210,6 @@
     if (brm)
 	*brm = bridges_removed;
 
-    G_verbose_message("Removed lines: %d", lines_removed);
-    G_verbose_message("Removed bridges: %d", bridges_removed);
+    G_verbose_message(_("Removed lines: %d"), lines_removed);
+    G_verbose_message(_("Removed bridges: %d"), bridges_removed);
 }

Modified: grass/trunk/lib/vector/Vlib/local_proto.h
===================================================================
--- grass/trunk/lib/vector/Vlib/local_proto.h	2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/local_proto.h	2013-04-01 15:15:14 UTC (rev 55582)
@@ -3,9 +3,8 @@
 
 #include <grass/vector.h>
 
-void V2__add_line_to_topo_nat(struct Map_info *, int ,
-                              const struct line_pnts *, const struct line_cats *,
-                              int (*external_routine) (const struct Map_info *, int));
+/* Internal vector library subroutines which are not part of public
+   API*/
 
 /* map.c */
 int Vect__delete(const char *, int);
@@ -16,4 +15,11 @@
 char *Vect__get_path(const struct Map_info *);
 char *Vect__get_element_path(const struct Map_info *, const char *);
 
+/* write_nat.c */
+int V2__add_line_to_topo_nat(struct Map_info *, off_t, int,
+                             const struct line_pnts *, const struct line_cats *, int,
+                             int (*external_routine) (const struct Map_info *, int));
+int V2__delete_line_from_topo_nat(struct Map_info *, int, int,
+                                  const struct line_pnts *, const struct line_cats *);
+
 #endif /* PG_LOCAL_PROTO_H__ */

Modified: grass/trunk/lib/vector/Vlib/open.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open.c	2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/open.c	2013-04-01 15:15:14 UTC (rev 55582)
@@ -782,6 +782,8 @@
     /* set 2D/3D */
     Map->plus.spidx_with_z = Map->plus.with_z = Map->head.with_z = (with_z != 0);
 
+    Map->level = LEVEL_1;
+    
     if ((*Open_new_array[Map->format][1]) (Map, name, with_z) < 0) {
         if (getenv("GRASS_VECTOR_PGFILE") == NULL)  /* GRASS_VECTOR_PGFILE defined by v.out.postgis */
             Vect_delete(name); /* clean up */
@@ -798,7 +800,6 @@
     Vect_open_sidx(Map, 2);
 
     Map->open = VECT_OPEN_CODE;
-    Map->level = 1;
     Map->head_only = FALSE;
     Map->support_updated = FALSE;
     Map->plus.built = GV_BUILD_NONE;

Modified: grass/trunk/lib/vector/Vlib/read.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read.c	2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/read.c	2013-04-01 15:15:14 UTC (rev 55582)
@@ -5,7 +5,7 @@
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   (C) 2001-2009, 2011 by the GRASS Development Team
+   (C) 2001-2009, 2011-2013 by the GRASS Development Team
 
    This program is free software under the GNU General Public License
    (>=v2). Read the file COPYING that comes with GRASS for details.
@@ -83,13 +83,16 @@
   \param Map pointer to Map_info struct
 
   \return feature id
+  \return -1 on error
 */
 int Vect_get_next_line_id(const struct Map_info *Map)
 {
     G_debug(3, "Vect_get_next_line()");
 
-    if (!VECT_OPEN(Map))
-	G_fatal_error(_("Vector map is not open for reading"));
+    if (!VECT_OPEN(Map)) {
+	G_warning(_("Vector map is not open for reading"));
+        return -1;
+    }
     
     return Map->next_line - 1;
 }
@@ -99,17 +102,17 @@
 
    This function implements sequential access, constraints are
    reflected, see Vect_set_constraint_region(),
-   Vect_set_constraint_type(), or Vect_set_constraint_field().
+   Vect_set_constraint_type(), or Vect_set_constraint_field() for
+   details.
      
-   Use Vect_rewind() to reset reading.
+   Use Vect_rewind() to reset reading. Topological level is not
+   required.
 
-   G_fatal_error() is called on failure.
+   A warning is printed on failure.
    
    \param Map pointer Map_info struct
-   \param[out] line_p feature geometry
-   (pointer to line_pnts struct)
-   \param[out] line_c feature categories
-   (pointer to line_cats struct)
+   \param[out] line_p feature geometry (pointer to line_pnts struct)
+   \param[out] line_c feature categories (pointer to line_cats struct)
 
    \return feature type (GV_POINT, GV_LINE, ...)
    \return -1 on error
@@ -122,32 +125,32 @@
     
     G_debug(3, "Vect_read_next_line(): next_line = %d", Map->next_line);
 
-    if (!VECT_OPEN(Map))
-	G_fatal_error(_("Vector map is not open for reading"));
+    if (!VECT_OPEN(Map)) {
+	G_warning(_("Vector map is not open for reading"));
+        return -1;
+    }
     
     ret = (*Read_next_line_array[Map->format][Map->level]) (Map, line_p,
 							    line_c);
-    /* 
     if (ret == -1)
-	G_fatal_error(_("Unable to read feature %d vector map <%s>"),
-		      Map->next_line, Vect_get_full_name(Map));
-    */
+        G_warning(_("Unable to read feature %d from vector map <%s>"),
+                  Map->next_line, Vect_get_full_name(Map));
+    
     return ret;
 }
 
 /*!
-   \brief Read vector feature
+   \brief Read vector feature (topological level required)
 
-   This function implements random access. Note that constraits are
-   ignored!
+   This function implements random access. Constraits are ignored.
 
-   G_fatal_error() is called on failure.
+   Note: Topology must be built at level >= GV_BUILD_BASE
+
+   A warning is printed on failure.
    
    \param Map pointer to vector map
-   \param[out] line_p feature geometry
-   (pointer to line_pnts struct)
-   \param[out] line_c feature categories
-   (pointer to line_cats struct)
+   \param[out] line_p feature geometry (pointer to line_pnts struct)
+   \param[out] line_c feature categories (pointer to line_cats struct)
    \param line feature id (starts at 1)
    
    \return feature type
@@ -161,35 +164,43 @@
     
     G_debug(3, "Vect_read_line(): line = %d", line);
 
-    if (!VECT_OPEN(Map))
-	G_fatal_error(_("Vector map is not open for reading"));
-
-    if (line < 1 || line > Map->plus.n_lines)
-	G_fatal_error(_("Requested feature id %d is not reasonable"
-			"(max features in vector map <%s>: %d)"),
-		      line, Vect_get_full_name(Map), Map->plus.n_lines);
-
+    if (!VECT_OPEN(Map)) {
+	G_warning(_("Vector map is not open for reading"));
+        return -1;
+    }
+    
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
+    }
+    
     ret = (*Read_line_array[Map->format]) (Map, line_p, line_c, line);
 
-    /*
     if (ret == -1)
-	G_fatal_error(_("Unable to read feature %d from vector map <%s>"),
-		      line, Vect_get_full_name(Map));
-    */
+	G_warning(_("Unable to read feature %d from vector map <%s>"),
+                  line, Vect_get_full_name(Map));
+    
     return ret;
 }
 
 /*!
-  \brief Check if feature is alive or dead (level 2 required)
+  \brief Check if feature is alive or dead (topological level required)
   
+  Note: Topology must be built at level >= GV_BUILD_BASE
+
   \param Map pointer to Map_info structure
   \param line feature id
   
   \return 1 feature alive
   \return 0 feature is dead
+  \return -1 on error
  */
 int Vect_line_alive(const struct Map_info *Map, int line)
 {
+    if (line < 1 || line > Map->plus.n_lines) {
+        return -1;
+    }
+
     if (Map->plus.Line[line] != NULL)
 	return 1;
     
@@ -197,8 +208,10 @@
 }
 
 /*!
-  \brief Check if node is alive or dead (level 2 required)
+  \brief Check if node is alive or dead (topological level required)
   
+  Note: Topology must be built at level >= GV_BUILD_BASE
+
   \param Map pointer to Map_info structure
   \param node node id
   
@@ -207,6 +220,10 @@
  */
 int Vect_node_alive(const struct Map_info *Map, int node)
 {
+    if (node < 1 || node > Map->plus.n_nodes) {
+        return -1;
+    }
+
     if (Map->plus.Node[node] != NULL)
 	return 1;
 
@@ -214,16 +231,22 @@
 }
 
 /*!
-  \brief Check if area is alive or dead (level 2 required)
+  \brief Check if area is alive or dead (topological level required)
   
+  Note: Topology must be built at level >= GV_BUILD_AREAS
+
   \param Map pointer to Map_info structure
   \param area area id
   
   \return 1 area alive
   \return 0 area is dead
+  \return -1 on error
 */
 int Vect_area_alive(const struct Map_info *Map, int area)
 {
+    if (area < 1 || area > Map->plus.n_areas)
+        return -1;
+    
     if (Map->plus.Area[area] != NULL)
 	return 1;
 
@@ -231,8 +254,10 @@
 }
 
 /*!
-  \brief Check if isle is alive or dead (level 2 required)
+  \brief Check if isle is alive or dead (topological level required)
 
+  Note: Topology must be built at level >= GV_BUILD_AREAS
+  
   \param Map pointer to Map_info structure
   \param isle isle id
   
@@ -241,6 +266,9 @@
 */
 int Vect_isle_alive(const struct Map_info *Map, int isle)
 {
+    if (isle < 1 || isle > Map->plus.n_isles)
+        return -1;
+
     if (Map->plus.Isle[isle] != NULL)
 	return 1;
 
@@ -248,8 +276,10 @@
 }
 
 /*!
-  \brief Get feature offset
+  \brief Get feature offset (topological level required)
   
+  Note: Topology must be built at level >= GV_BUILD_BASE
+  
   Used for Vect_restore_line().
   
   \param Map pointer to Map_info structure
@@ -260,8 +290,9 @@
 */
 off_t Vect_get_line_offset(const struct Map_info *Map, int line)
 {
-    if (line < 1 || line > Map->plus.n_lines)
+    if (line < 1 || line > Map->plus.n_lines) {
 	return -1;
+    }
     
     if (Map->plus.Line[line] != NULL) {
 	return Map->plus.Line[line]->offset;

Modified: grass/trunk/lib/vector/Vlib/read_nat.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_nat.c	2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/read_nat.c	2013-04-01 15:15:14 UTC (rev 55582)
@@ -122,11 +122,11 @@
   This function implements random access for native format,
   constraints are ignored!
   
+  Note: Topology must be built at level >= GV_BUILD_BASE
+  
   \param Map pointer to Map_info struct 
-  \param[out] Points container used to store line points within
-  (pointer to line_pnts struct)
-  \param[out] Cats container used to store line categories within
-  (pointer to line_cats struct)
+  \param[out] Points container used to store line points within (pointer to line_pnts struct)
+  \param[out] Cats container used to store line categories within (pointer to line_cats struct)
   \param line feature id to read (starts at 1)
   
   \return feature type (GV_POINT, GV_LINE, ...)
@@ -140,10 +140,14 @@
 
     G_debug(3, "V2_read_line_nat(): line = %d", line);
 
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
+    }
+    
     Line = Map->plus.Line[line];
-
     if (Line == NULL) {
-	G_warning(_("Attempt to read dead feature %d"), line);
+	G_warning(_("Attempt to access dead feature %d"), line);
 	return -1;
     }
 

Modified: grass/trunk/lib/vector/Vlib/read_sfa.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_sfa.c	2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/read_sfa.c	2013-04-01 15:15:14 UTC (rev 55582)
@@ -24,6 +24,8 @@
  
   This function implements random access on level 2.
   
+  Note: Topology must be built at level >= GV_BUILD_BASE
+  
   \param Map pointer to Map_info structure
   \param[out] line_p container used to store line points within
   (pointer to line_pnts struct)
@@ -44,9 +46,14 @@
     
     G_debug(4, "V2_read_line_sfa() line = %d", line);
     
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
+    }
+
     Line = Map->plus.Line[line];
     if (Line == NULL) {
-        G_warning(_("Attempt to read dead feature %d"), line);
+        G_warning(_("Attempt to access dead feature %d"), line);
         return -1;
     }
     
@@ -106,9 +113,11 @@
     else
         type = V1_read_line_ogr(Map, line_p, line_c, Line->offset);
 
-    if (type != Line->type)
-        G_fatal_error(_("Unexpected feature type (%d) - should be (%d)"),
-                      type, Line->type);
+    if (type != Line->type) {
+        G_warning(_("Unexpected feature type (%d) - should be (%d)"),
+                  type, Line->type);
+        return -1;
+    }
 
     return type;
 #else

Modified: grass/trunk/lib/vector/Vlib/write.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write.c	2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/write.c	2013-04-01 15:15:14 UTC (rev 55582)
@@ -5,20 +5,19 @@
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   Operations:
-    - Write new feature
-    - Rewrite feature
-    - Delete feature
+   Supported operations:
+    - Write a new feature
+    - Rewrite existing feature
+    - Delete existing feature
     - Restore deleted feature
 
-   (C) 2001-2010, 2012 by the GRASS Development Team
+   (C) 2001-2010, 2012-2013 by the GRASS Development Team
 
    This program is free software under the GNU General Public License
    (>=v2). Read the file COPYING that comes with GRASS for details.
 
    \author Radim Blazek
-   \author Updated by Martin Landa <landa.martin gmail.com>
-   (restore lines, OGR & PostGIS support)
+   \author Updated by Martin Landa <landa.martin gmail.com> (restore lines, OGR & PostGIS support)
  */
 
 #include <sys/types.h>
@@ -104,7 +103,7 @@
 #endif
 #ifdef HAVE_POSTGRES
     , {
-	rewrite_dummy, V1_rewrite_line_pg, V2_rewrite_line_sfa}
+	rewrite_dummy, V1_rewrite_line_pg, V2_rewrite_line_pg}
 #else
     , {
 	rewrite_dummy, format_l, format_l}
@@ -127,7 +126,7 @@
 #endif
 #ifdef HAVE_POSTGRES
     , {
-	delete_dummy, V1_delete_line_pg, V2_delete_line_sfa}
+	delete_dummy, V1_delete_line_pg, V2_delete_line_pg}
 #else
     , {
 	delete_dummy, format, format}
@@ -157,20 +156,22 @@
 #endif
 };
 
+static int check_map(const struct Map_info *);
+
 /*!
-   \brief Writes new feature
+   \brief Writes a new feature
 
    New feature is written to the end of file (in the case of native
-   format). Vector map topology is not required.
+   format). Topological level is not required.
 
-   Calls G_fatal_error() when vector map is not opened.
+   A warning is printed on error.
    
    \param Map pointer to Map_info structure
    \param type feature type (see dig_defines.h for supported types)
-   \param points ointer to line_pnts structure (feature geometry)
+   \param points pointer to line_pnts structure (feature geometry)
    \param cats pointer to line_cats structure (feature categories)
 
-   \return new feature id (on level 2)
+   \return new feature id (on level 2) (or 0 when build level < GV_BUILD_BASE)
    \return offset into file where the feature starts (on level 1)
    \return -1 on error
  */
@@ -182,44 +183,42 @@
     G_debug(3, "Vect_write_line(): name = %s, format = %d, level = %d",
 	    Map->name, Map->format, Map->level);
 
-    if (!VECT_OPEN(Map))
-	G_fatal_error(_("Unable to write feature, vector map is not opened"));
-
+    if (!VECT_OPEN(Map)) {
+	G_warning(_("Vector map <%s> is not opened"), Vect_get_name(Map));
+        return -1;
+    }
+    
     if (!(Map->plus.update_cidx)) {
-	Map->plus.cidx_up_to_date = FALSE;
+	Map->plus.cidx_up_to_date = FALSE; /* category index will be outdated */
     }
 
     offset = 
 	(*Vect_write_line_array[Map->format][Map->level]) (Map, type, points,
 							   cats);
     
-    /*
-    if (offset == -1)
-	G_fatal_error(_("Unable to write feature (negative offset)"));
-    */
+    if (offset < 0)
+	G_warning(_("Unable to write feature in vector map <%s>"), Vect_get_name(Map));
     
-    /* note: returns new feature id on level 2 and file offset on
-       level 1 */
     return offset;
 }
 
 /*!
-   \brief Rewrites feature info at the given offset.
+   \brief Rewrites existing feature (topological level required)
 
-   Vector map must be opened with full topology (level 2).
+   Note: Topology must be built at level >= GV_BUILD_BASE
+   
+   A warning is printed on error.
 
    The number of points or cats or type may change. If necessary, the
    old feature is deleted and new is written.
 
-   This function calls G_fatal_error() on error.
-
    \param Map pointer to Map_info structure
    \param line feature id
    \param type feature type (GV_POINT, GV_LINE, ...)
    \param points feature geometry
    \param cats feature categories
 
-   \return feature offset
+   \return new feature offset
    \return -1 on error
  */
 off_t Vect_rewrite_line(struct Map_info *Map, int line, int type,
@@ -227,33 +226,39 @@
 {
     off_t ret, offset;
     
-    if (!VECT_OPEN(Map))
-	G_fatal_error(_("Unable to rewrite feature, vector map is not opened"));
+    if (!check_map(Map))
+        return -1;
 
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
+    }
+    
     if (!(Map->plus.update_cidx)) {
-	Map->plus.cidx_up_to_date = FALSE;
+	Map->plus.cidx_up_to_date = FALSE; /* category index will be outdated */
     }
 
     offset = Map->plus.Line[line]->offset;
-    G_debug(3, "Vect_rewrite_line(): name = %s, line = %d offset = %lu",
+    
+    G_debug(3, "Vect_rewrite_line(): name = %s, line = %d, offset = %lu",
 	    Map->name, line, offset);
+    
     ret = (*Vect_rewrite_line_array[Map->format][Map->level]) (Map, line, type,
 							       offset,
 							       points, cats);
-    /*
     if (ret == -1)
-	G_fatal_error(_("Unable to rewrite feature %d"), line);
-    */
+        G_warning(_("Unable to rewrite feature %d in vector map <%s>"), line, Vect_get_name(Map));
+
     return ret;
 }
 
 /*!
-   \brief Delete feature
+   \brief Delete existing feature (topological level required)
 
-   Vector map must be opened with full topology (level 2).
+   Note: Topology must be built at level >= GV_BUILD_BASE
+   
+   A warning is printed on error.
 
-   This function calls G_fatal_error() on error.
-
    \param Map pointer to Map_info structure
    \param line feature id
 
@@ -266,41 +271,37 @@
 
     G_debug(3, "Vect_delete_line(): name = %s, line = %d", Map->name, line);
 
-    if (Map->level < 2) {
-	G_fatal_error(_("Unable to delete feature %d, "
-			"vector map <%s> is not opened on topology level"),
-		      line, Map->name);
+    if (!check_map(Map))
+        return -1;
+    
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
     }
 
-    if (Map->mode != GV_MODE_RW && Map->mode != GV_MODE_WRITE) {
-	G_fatal_error(_("Unable to delete feature %d, "
-			"vector map <%s> is not opened in 'write' mode"),
-		      line, Map->name);
-    }
-
     if (!(Map->plus.update_cidx)) {
-	Map->plus.cidx_up_to_date = FALSE;
+	Map->plus.cidx_up_to_date = FALSE; /* category index will be outdated */
     }
 
     ret = (*Vect_delete_line_array[Map->format][Map->level]) (Map, line);
 
-    /*
     if (ret == -1)
-	G_fatal_error(_("Unable to delete feature id %d from vector map <%s>"),
-		      line, Vect_get_full_name(Map));
-    */
+	G_warning(_("Unable to delete feature %d from vector map <%s>"),
+                  line, Vect_get_name(Map));
+
     return ret;
 }
 
 /*!
-   \brief Restore previously deleted feature
+   \brief Restore previously deleted feature (topological level required)
 
-   Vector map must be opened with full topology (level 2).
+   Note: Topology must be built at level >= GV_BUILD_BASE
+   
+   A warning is printed on error.
 
-   This function calls G_fatal_error() on error.
-
    \param Map pointer to Map_info structure
    \param line feature id to be restored
+   \param offset feature offset
 
    \return 0 on success
    \return -1 on error
@@ -311,16 +312,12 @@
 
     G_debug(3, "Vect_restore_line(): name = %s, line = %d", Map->name, line);
 
-    if (Map->level < 2) {
-	G_fatal_error(_("Unable to restore feature %d, "
-			"vector map <%s> is not opened on topology level"),
-		      line, Map->name);
-    }
+    if (!check_map(Map))
+        return -1;
 
-    if (Map->mode != GV_MODE_RW && Map->mode != GV_MODE_WRITE) {
-	G_fatal_error(_("Unable to restore feature %d, "
-			"vector map <%s> is not opened in 'write' mode"),
-		      line, Map->name);
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
     }
 
     if (!(Map->plus.update_cidx)) {
@@ -329,10 +326,31 @@
 
     ret = (*Vect_restore_line_array[Map->format][Map->level]) (Map, line, offset);
 
-    /*
     if (ret == -1)
-	G_fatal_error(_("Unable to restore feature %d from vector map <%s>"),
-		      line, Map->name);
-    */
+	G_warning(_("Unable to restore feature %d in vector map <%s>"),
+                  line, Vect_get_name(Map));
+
     return ret;
 }
+
+int check_map(const struct Map_info *Map)
+{
+    if (!VECT_OPEN(Map)) {
+	G_warning(_("Vector map <%s> is not opened"), Vect_get_name(Map));
+        return 0;
+    }
+    
+    if (Map->level < 2) {
+	G_warning(_("Vector map <%s> is not opened on topology level"),
+                  Vect_get_name(Map));
+        return 0;
+    }
+
+    if (Map->mode != GV_MODE_RW && Map->mode != GV_MODE_WRITE) {
+	G_warning(_("Vector map <%s> is not opened in write mode"),
+                  Vect_get_name(Map));
+        return 0;
+    }
+    
+    return 1;
+}

Modified: grass/trunk/lib/vector/Vlib/write_nat.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_nat.c	2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/write_nat.c	2013-04-01 15:15:14 UTC (rev 55582)
@@ -1,11 +1,11 @@
 /*!
    \file lib/vector/Vlib/write_nat.c
 
-   \brief Vector library - write/modify vector feature (native format)
+   \brief Vector library - write/modify/delete vector feature (native format)
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   (C) 2001-2012 by the GRASS Development Team
+   (C) 2001-2013 by the GRASS Development Team
 
    This program is free software under the GNU General Public License
    (>=v2). Read the file COPYING that comes with GRASS for details.
@@ -24,298 +24,16 @@
 
 #include "local_proto.h"
 
+static struct line_cats *Cats;
+static struct line_pnts *Points;
+
 static off_t V1__rewrite_line_nat(struct Map_info *, off_t, int,
 				  const struct line_pnts *, const struct line_cats *);
+static void V2__delete_area_cats_from_cidx_nat(struct Map_info *, int);
+static void V2__add_area_cats_to_cidx_nat(struct Map_info *, int);
 
-/*! 
-  \brief Deletes area (i.e. centroid) categories from category
-  index (internal use only)
-
-  Call G_fatal_error() when area do not exits.
-  
-  \param Map pointer to Map_info structure
-  \param area area id
-*/
-static void V2__delete_area_cats_from_cidx_nat(struct Map_info *Map, int area)
-{
-    int i;
-    struct P_area *Area;
-    static struct line_cats *Cats = NULL;
-
-    G_debug(3, "V2__delete_area_cats_from_cidx_nat(), area = %d", area);
-
-    Area = Map->plus.Area[area];
-    if (!Area)
-	G_fatal_error(_("%s: Area %d does not exist"),
-		      "delete_area_cats_from_cidx()", area);
-    
-    if (Area->centroid == 0) /* no centroid found */
-	return;
-
-    if (!Cats)
-	Cats = Vect_new_cats_struct();
-
-    V2_read_line_nat(Map, NULL, Cats, Area->centroid);
-
-    for (i = 0; i < Cats->n_cats; i++) {
-	dig_cidx_del_cat(&(Map->plus), Cats->field[i], Cats->cat[i], area,
-			 GV_AREA);
-    }
-}
-
-/*! 
-  \brief Adds area (i.e. centroid) categories from category index
-  (internal use only)
-
-  Call G_fatal_error() when area do not exits.
-  
-  \param Map pointer to Map_info structure
-  \param area area id
-*/
-static void V2__add_area_cats_to_cidx_nat(struct Map_info *Map, int area)
-{
-    int i;
-    struct P_area *Area;
-    static struct line_cats *Cats = NULL;
-
-    G_debug(3, "V2__add_area_cats_to_cidx_nat(), area = %d", area);
-
-    Area = Map->plus.Area[area];
-    if (!Area)
-	G_fatal_error(_("%s: Area %d does not exist"),
-		      "add_area_cats_to_cidx():", area);
-
-    if (Area->centroid == 0) /* no centroid found */
-	return;
-
-    if (!Cats)
-	Cats = Vect_new_cats_struct();
-
-    V2_read_line_nat(Map, NULL, Cats, Area->centroid);
-
-    for (i = 0; i < Cats->n_cats; i++) {
-	dig_cidx_add_cat_sorted(&(Map->plus), Cats->field[i], Cats->cat[i],
-				area, GV_AREA);
-    }
-}
-
 /*!
-  \brief Add feature (line) to topo file (internal use only)
-
-  Update areas. Areas are modified if: 
-   
-  1) first or/and last point are existing nodes ->
-   - drop areas/islands whose boundaries are neighbour to this boundary at these nodes
-   - try build areas and islands for this boundary and neighbour boundaries going through these nodes
-
-   Question: may be by adding line created new area/isle which doesn't go through nodes of this line
-
-   <pre>
-             old         new line 
-         +----+----+                    +----+----+                 +----+----+ 
-         | A1 | A2 |  +      /      ->  | A1 |   /|   or +   \   -> | A1 | A2 | \
-         |    |    |                    |    |    |                 |    |    |
-         +----+----+                    +----+----+                 +----+----+
-           I1   I1                        I1   I1                      
-   </pre>        
- 
-   - re-attach all centroids/isles inside new area(s)
-   - attach new isle to area outside
-
-  2) line is closed ring (node at the end is new, so it is not case above)
-    - build new area/isle
-    - check if it is island or contains island(s)
-    - re-attach all centroids/isles inside new area(s)
-    - attach new isle to area outside
-    
-    Note that 1) and 2) is done by the same code.
-
-    \param Map pointer to Map_info structure
-    \param line feature id
-    \param points pointer to line_pnts structure (feature's geometry)
-    \param cats pointer to line_cats structure (feature's categories)
-*/
-void V2__add_line_to_topo_nat(struct Map_info *Map, int line,
-                              const struct line_pnts *points, const struct line_cats *cats,
-                              int (*external_routine) (const struct Map_info *, int))
-{
-    int first, s, n, i;
-    int type, node, next_line, area, side, sel_area, new_area[2];
-
-    struct Plus_head *plus;
-    struct P_line *Line, *NLine;
-    struct P_node *Node;
-    struct P_area *Area;
-    
-    struct bound_box box, abox;
-    
-    G_debug(3, "V2__add_line_to_topo_nat(), line = %d", line);
-
-    plus = &(Map->plus);
-    Line = plus->Line[line];
-    type = Line->type;
-
-    if (plus->built >= GV_BUILD_AREAS &&
-	type == GV_BOUNDARY) {
-	struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
-	
-	/* Delete neighbour areas/isles */
-	first = TRUE;
-	for (s = 0; s < 2; s++) {	/* for each node */
-	    node = (s == 0 ? topo->N1 : topo->N2);
-	    G_debug(3,
-		    "  delete neighbour areas/isles: %s node = %d",
-		    (s == 0 ? "first" : "second"), node);
-	    Node = plus->Node[node];
-	    n = 0;
-	    for (i = 0; i < Node->n_lines; i++) {
-		NLine = plus->Line[abs(Node->lines[i])];
-		if (NLine->type == GV_BOUNDARY)
-		    n++;
-	    }
-	    
-	    G_debug(3, "  number of boundaries at node = %d", n);
-	    if (n > 2) {
-		/* more than 2 boundaries at node ( >= 2 old + 1 new ) */
-		/* Line above (to the right), it is enough to check to
-		   the right, because if area/isle exists it is the
-		   same to the left */
-		if (!s)
-		    next_line =
-			dig_angle_next_line(plus, line, GV_RIGHT,
-					    GV_BOUNDARY, NULL);
-		else
-		    next_line =
-			dig_angle_next_line(plus, -line, GV_RIGHT,
-					    GV_BOUNDARY, NULL);
-		
-		if (next_line != 0) {	/* there is a boundary to the right */
-		    NLine = plus->Line[abs(next_line)];
-		    topo = (struct P_topo_b *)NLine->topo;
-		    if (next_line > 0)	/* the boundary is connected by 1. node */
-			/* we are interested just in this side (close to our line) */
-			area = topo->right;	
-		    else if (next_line < 0)	/* the boundary is connected by 2. node */
-			area = topo->left;
-		    
-		    G_debug(3, "  next_line = %d area = %d", next_line,
-			    area);
-		    if (area > 0) {	/* is area */
-			Vect_get_area_box(Map, area, &box);
-			if (first) {
-			    Vect_box_copy(&abox, &box);
-			    first = FALSE;
-			}
-			else
-			    Vect_box_extend(&abox, &box);
-			
-			if (plus->update_cidx) {
-			    V2__delete_area_cats_from_cidx_nat(Map, area);
-			}
-			dig_del_area(plus, area);
-                        if (external_routine) /* call external subroutine if defined */
-                            external_routine(Map, area);
-		    }
-		    else if (area < 0) {	/* is isle */
-			dig_del_isle(plus, -area);
-                        if (external_routine)  /* call external subroutine if defined */
-                            external_routine(Map, area);
-		    }
-		}
-	    }
-	}
-	/* Build new areas/isles.
-	 * It's true that we deleted also adjacent areas/isles, but
-	 * if they form new one our boundary must participate, so
-	 * we need to build areas/isles just for our boundary */
-	for (s = 0; s < 2; s++) {
-	    side = (s == 0 ? GV_LEFT : GV_RIGHT);
-	    area = Vect_build_line_area(Map, line, side);
-	    
-	    if (area > 0) {	/* area */
-		Vect_get_area_box(Map, area, &box);
-		if (first) {
-		    Vect_box_copy(&abox, &box);
-		    first = FALSE;
-		}
-		else
-		    Vect_box_extend(&abox, &box);
-	    }
-	    else if (area < 0) {
-		/* isle -> must be attached -> add to abox */
-		Vect_get_isle_box(Map, -area, &box);
-		if (first) {
-		    Vect_box_copy(&abox, &box);
-		    first = FALSE;
-		}
-		else
-		    Vect_box_extend(&abox, &box);
-	    }
-	    new_area[s] = area;
-	}
-	/* Reattach all centroids/isles in deleted areas + new area.
-	 * Because isles are selected by box it covers also possible
-	 * new isle created above */
-	if (!first) { /* i.e. old area/isle was deleted or new one created */
-	    /* Reattach isles */
-	    if (plus->built >= GV_BUILD_ATTACH_ISLES)
-		Vect_attach_isles(Map, &abox);
-	    
-	    /* Reattach centroids */
-	    if (plus->built >= GV_BUILD_CENTROIDS)
-		Vect_attach_centroids(Map, &abox);
-	}
-	/* Add to category index */
-	if (plus->update_cidx) {
-	    for (s = 0; s < 2; s++) {
-		if (new_area[s] > 0) {
-		    V2__add_area_cats_to_cidx_nat(Map, new_area[s]);
-		}
-	    }
-	}
-    }
-    
-    /* Attach centroid */
-    if (plus->built >= GV_BUILD_CENTROIDS) {
-	struct P_topo_c *topo;
-
-	if (type == GV_CENTROID) {
-	    sel_area = Vect_find_area(Map, points->x[0], points->y[0]);
-	    G_debug(3, "  new centroid %d is in area %d", line, sel_area);
-	    if (sel_area > 0) {
-		Area = plus->Area[sel_area];
-		Line = plus->Line[line];
-		topo = (struct P_topo_c *)Line->topo;
-		if (Area->centroid == 0) {	/* first centroid */
-		    G_debug(3, "  first centroid -> attach to area");
-		    Area->centroid = line;
-		    topo->area = sel_area;
-		    if (plus->update_cidx) {
-			V2__add_area_cats_to_cidx_nat(Map, sel_area);
-		    }
-		}
-		else {		/* duplicate centroid */
-		    G_debug(3,
-			    "  duplicate centroid -> do not attach to area");
-		    topo->area = -sel_area;
-		}
-	    }
-	}
-    }
-
-    /* Add category index */
-    if (cats) {
-        for (i = 0; i < cats->n_cats; i++) {
-            dig_cidx_add_cat_sorted(plus, cats->field[i], cats->cat[i], line,
-                                    type);
-        }
-    }
-    
-    return;
-}
-
-/*!
-  \brief Writes feature to 'coor' file (level 1)
+  \brief Writes feature to 'coor' file at level 1 (internal use only)
   
   \param Map pointer to Map_info structure
   \param type feature type (GV_POINT, GV_LINE, ...)
@@ -325,8 +43,8 @@
   \return feature offset into file
   \return -1 on error
 */
-off_t V1_write_line_nat(struct Map_info *Map,
-		       int type, const struct line_pnts *points, const struct line_cats *cats)
+off_t V1_write_line_nat(struct Map_info *Map, int type,
+                        const struct line_pnts *points, const struct line_cats *cats)
 {
     off_t offset;
 
@@ -334,6 +52,7 @@
 	return -1;
 
     offset = dig_ftell(&(Map->dig_fp));
+    G_debug(3, "V1_write_line_nat(): offset = %lu", offset);
     if (offset == -1)
 	return -1;
 
@@ -342,65 +61,46 @@
 
 /*!
   \brief Writes feature to 'coor' file at topological level (internal use only)
+
+  Note: Function returns feature id, but is defined as off_t for
+  compatibility with level 1 functions.
   
   \param Map pointer to Map_info structure
   \param type feature type (GV_POINT, GV_LINE, ...)
   \param points feature geometry
   \param cats feature categories
   
-  \return new feature id
+  \return new feature id 
+  \return 0 topology is not requested to be built (build level < GV_BUILD_BASE)
   \return -1 on error
 */
 off_t V2_write_line_nat(struct Map_info *Map, int type,
 			const struct line_pnts *points, const struct line_cats *cats)
 {
-    int line;
     off_t offset;
-    struct Plus_head *plus;
-    struct bound_box box;
 
-    line = 0;
+    G_debug(3, "V2_write_line_nat(): type=%d", type);
     
-    G_debug(3, "V2_write_line_nat()");
+    /* write feature to 'coor' file */
     offset = V1_write_line_nat(Map, type, points, cats);
     if (offset < 0)
 	return -1;
 
-    /* Update topology */
-    plus = &(Map->plus);
-    /* Add line */
-    if (plus->built >= GV_BUILD_BASE) {
-	dig_line_box(points, &box);
-	line = dig_add_line(plus, type, points, &box, offset);
-	G_debug(3, "  line added to topo with id = %d", line);
-	if (line == 1)
-	    Vect_box_copy(&(plus->box), &box);
-	else
-	    Vect_box_extend(&(plus->box), &box);
-    }
-
-    V2__add_line_to_topo_nat(Map, line, points, cats, NULL);
-
-    G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
-	    plus->uplist.n_upnodes);
-
-    /* returns int line, but is defined as off_t for compatibility with
-     * Vect_write_line_array in write.c */
-    
-    return line;
+    /* update topology (build level >= GV_BUILD_BASE) */
+    return V2__add_line_to_topo_nat(Map, offset, type, points, cats, -1, NULL);
 }
 
 /*!
-  \brief Rewrites feature at the given offset (level 1)
+  \brief Rewrites feature to 'coor' file at level 1 (internal use only)
   
-  If the number of points or cats differs from the original one or
-  the type is changed: GV_POINTS -> GV_LINES or GV_LINES ->
-  GV_POINTS, the old one is deleted and the new is appended to the
-  end of the file.
+  If the number of points or cats differs from the original one or the
+  type is changed: GV_POINTS -> GV_LINES or GV_LINES -> GV_POINTS, the
+  old one is deleted and the new is appended to the end of the file.
   
-  Old feature is deleted (marked as dead), new feature written.
+  Old feature is deleted (marked as dead), and a new feature written.
   
   \param Map pointer to Map_info structure
+  \param line feature id to be rewritten
   \param offset feature offset
   \param type feature type (GV_POINT, GV_LINE, ...)
   \param points feature geometry
@@ -458,14 +158,20 @@
 
 /*!
   \brief Rewrites feature to 'coor' file at topological level (internal use only)
+
+  Note: Topology must be built at level >= GV_BUILD_BASE
   
+  Note: Function returns feature id, but is defined as off_t for
+  compatibility with level 1 functions.
+  
   \param Map pointer to Map_info structure
-  \param type feature type  (GV_POINT, GV_LINE, ...)
-  \param line feature id
+  \param type feature type (GV_POINT, GV_LINE, ...)
+  \param line feature id to be rewritten
+  \param old_offset feature offset
   \param points feature geometry
   \param cats feature categories
   
-  \return offset where line was rewritten
+  \return new feature id
   \return -1 on error
 */
 off_t V2_rewrite_line_nat(struct Map_info *Map, int line, int type, off_t old_offset,
@@ -478,45 +184,216 @@
      *        angles not changed etc.) */
 
     off_t offset;
-    struct Plus_head *plus;
-    struct bound_box box;
 
-    V2_delete_line_nat(Map, line);
+    if (0 != V2_delete_line_nat(Map, line))
+        return -1;
     
     G_debug(3, "V2_write_line_nat(), line = %d", line);
+
+    /* rewrite feature in 'coor' file */
     offset = V1_rewrite_line_nat(Map, line, type, old_offset, points, cats);
     if (offset < 0)
 	return -1;
 
-    /* Update topology */
+    /* update topology */
+    return V2__add_line_to_topo_nat(Map, offset, type, points, cats, -1, NULL);
+}
+
+/*!
+  \brief Deletes feature at level 1 (internal use only)
+  
+  \param Map pointer Map_info structure
+  \param offset feature offset
+  
+  \return  0 on success
+  \return -1 on error
+*/
+int V1_delete_line_nat(struct Map_info *Map, off_t offset)
+{
+    char rhead;
+    struct gvfile *dig_fp;
+
+    G_debug(3, "V1_delete_line_nat(): offset = %lu", (unsigned long) offset);
+
+    dig_set_cur_port(&(Map->head.port));
+    dig_fp = &(Map->dig_fp);
+
+    if (dig_fseek(dig_fp, offset, 0) == -1)
+	return -1;
+
+    /* read old */
+    if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
+	return -1;
+
+    rhead &= 0xFE;
+
+    if (dig_fseek(dig_fp, offset, 0) == -1)
+	return -1;
+
+    if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
+	return -1;
+
+    if (0 != dig_fflush(dig_fp))
+	return -1;
+
+    return 0;
+}
+
+/*!
+  \brief Deletes feature at topological level (internal use only)
+
+  Note: Topology must be built at level >= GV_BUILD_BASE  
+  
+  \param pointer to Map_info structure
+  \param line feature id
+  
+  \return 0 on success
+  \return -1 on error
+*/
+int V2_delete_line_nat(struct Map_info *Map, int line)
+{
+    int type;
+    struct P_line *Line;
+    struct Plus_head *plus;
+
+    G_debug(3, "V2_delete_line_nat(): line = %d", line);
+
+    Line = NULL;
     plus = &(Map->plus);
-    /* Add line */
-    if (plus->built >= GV_BUILD_BASE) {
-	dig_line_box(points, &box);
-	line = dig_add_line(plus, type, points, &box, offset);
-	G_debug(3, "  line added to topo with id = %d", line);
-	if (line == 1)
-	    Vect_box_copy(&(plus->box), &box);
-	else
-	    Vect_box_extend(&(plus->box), &box);
+
+    if (line < 1 || line > plus->n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
     }
+    
+    Line = Map->plus.Line[line];
+    if (Line == NULL) {
+        G_warning(_("Attempt to access dead feature %d"), line);
+        return -1;
+    }
 
-    V2__add_line_to_topo_nat(Map, line, points, cats, NULL);
+    /* read the line */    
+    if (!Points) {
+	Points = Vect_new_line_struct();
+    }
+    if (!Cats) {
+	Cats = Vect_new_cats_struct();
+    }
+    type = V2_read_line_nat(Map, Points, Cats, line);
+    if (type < 0)
+        return -1;
 
-    G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
-	    plus->uplist.n_upnodes);
+    /* delete feature from coor file */
+    if (0 != V1_delete_line_nat(Map, Line->offset))
+        return -1;
 
-    /* returns int line, but is defined as off_t for compatibility with
-     * Vect_rewrite_line_array in write.c */
+    /* delete feature from topology */
+    if (0 != V2__delete_line_from_topo_nat(Map, line, type, Points, Cats))
+        return -1;
     
-    return line;
+    return 0;
 }
 
 /*!
-  \brief Rewrites feature at the given offset.
+  \brief Restores feature at level 1 (internal use only)
   
   \param Map pointer to Map_info structure
   \param offset feature offset
+  
+  \return  0 on success
+  \return -1 on error
+*/
+int V1_restore_line_nat(struct Map_info *Map, off_t offset)
+{
+    char rhead;
+    struct gvfile *dig_fp;
+    
+    G_debug(3, "V1_restore_line_nat(), offset = %lu", (unsigned long) offset);
+    
+    dig_set_cur_port(&(Map->head.port));
+    dig_fp = &(Map->dig_fp);
+    
+    if (dig_fseek(dig_fp, offset, 0) == -1)
+	return -1;
+    
+    /* read old */
+    if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
+	return -1;
+
+    /* mark as alive */
+    rhead |= 1;
+    
+    /* write new */
+    if (dig_fseek(dig_fp, offset, 0) == -1)
+	return -1;
+
+    if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
+	return -1;
+    
+    if (0 != dig_fflush(dig_fp))
+	return -1;
+    
+    return 0;
+}
+
+/*!
+  \brief Restores feature at topological level (internal use only)
+
+  Note: This function requires build level >= GV_BUILD_BASE.
+  
+  \param Map pointer to Map_info structure
+  \param line feature id
+  \param offset feature offset
+  
+  \return 0 on success
+  \return -1 on error
+*/
+int V2_restore_line_nat(struct Map_info *Map, int line, off_t offset)
+{
+    int type;
+    struct Plus_head *plus;
+    struct P_line *Line;
+    
+    plus = &(Map->plus);
+
+    G_debug(3, "V2_restore_line_nat(), line = %d", line);
+
+    if (line < 1 || line > plus->n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
+    }
+    
+    Line = Map->plus.Line[line];
+    if (Line != NULL) {
+        G_warning(_("Attempt to access alive feature %d"), line);
+        return -1;
+    }
+    
+    /* restore feature in 'coor' file */
+    if (0 != V1_restore_line_nat(Map, offset))
+	return -1;
+
+
+    /* read feature geometry */    
+    if (!Points)
+	Points = Vect_new_line_struct();
+    if (!Cats)
+	Cats = Vect_new_cats_struct();
+    type = V1_read_line_nat(Map, Points, Cats, offset);
+    if (type < 0)
+	return -1;
+
+    /* update topology */
+    return V2__add_line_to_topo_nat(Map, offset, type, Points, Cats, line, NULL) > 0 ? 0 : -1;
+}
+
+/*** static or internal subroutines bellow ****/
+
+/*!
+  \brief Rewrites feature at the given offset 
+  
+  \param Map pointer to Map_info structure
+  \param offset feature offset
   \param type feature type  (GV_POINT, GV_LINE, ...)
   \param points feature geometry
   \param cats feature categories
@@ -611,109 +488,135 @@
     return offset;
 }
 
-/*!
-  \brief Deletes feature at the given offset (level 1)
+/*! 
+  \brief Deletes area (i.e. centroid) categories from category
+  index (internal use only)
+
+  Call G_fatal_error() when area do not exits.
   
-  \param Map pointer Map_info structure
-  \param offset feature offset
-  
-  \return  0 on success
-  \return -1 on error
+  \param Map pointer to Map_info structure
+  \param area area id
 */
-int V1_delete_line_nat(struct Map_info *Map, off_t offset)
+void V2__delete_area_cats_from_cidx_nat(struct Map_info *Map, int area)
 {
-    char rhead;
-    struct gvfile *dig_fp;
+    int i;
+    struct P_area *Area;
+    static struct line_cats *Cats = NULL;
 
-    G_debug(3, "V1_delete_line_nat(), offset = %lu", (unsigned long) offset);
+    G_debug(3, "V2__delete_area_cats_from_cidx_nat(), area = %d", area);
 
-    dig_set_cur_port(&(Map->head.port));
-    dig_fp = &(Map->dig_fp);
+    Area = Map->plus.Area[area];
+    if (!Area)
+	G_fatal_error(_("%s: Area %d does not exist"),
+		      "delete_area_cats_from_cidx()", area);
+    
+    if (Area->centroid == 0) /* no centroid found */
+	return;
 
-    if (dig_fseek(dig_fp, offset, 0) == -1)
-	return -1;
+    if (!Cats)
+	Cats = Vect_new_cats_struct();
 
-    /* read old */
-    if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
-	return (-1);
+    V2_read_line_nat(Map, NULL, Cats, Area->centroid);
 
-    rhead &= 0xFE;
+    for (i = 0; i < Cats->n_cats; i++) {
+	dig_cidx_del_cat(&(Map->plus), Cats->field[i], Cats->cat[i], area,
+			 GV_AREA);
+    }
+}
 
-    if (dig_fseek(dig_fp, offset, 0) == -1)
-	return -1;
+/*! 
+  \brief Adds area (i.e. centroid) categories from category index
+  (internal use only)
 
-    if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
-	return -1;
-
-    if (0 != dig_fflush(dig_fp))
-	return -1;
-
-    return 0;
-}
-
-/*!
-  \brief Deletes feature at topological level (internal use only)
+  Call G_fatal_error() when area do not exits.
   
-  \param pointer to Map_info structure
-  \param line feature id
-  
-  \return 0 on success
-  \return -1 on error
+  \param Map pointer to Map_info structure
+  \param area area id
 */
-int V2_delete_line_nat(struct Map_info *Map, int line)
+void V2__add_area_cats_to_cidx_nat(struct Map_info *Map, int area)
 {
-    int ret, i, side, type, first, next_line, area;
-    struct P_line *Line;
+    int i;
     struct P_area *Area;
-    struct Plus_head *plus;
-    struct bound_box box, abox;
-    int adjacent[4], n_adjacent;
     static struct line_cats *Cats = NULL;
-    static struct line_pnts *Points = NULL;
 
-    G_debug(3, "V2_delete_line_nat(), line = %d", line);
+    G_debug(3, "V2__add_area_cats_to_cidx_nat(), area = %d", area);
 
-    type = first = n_adjacent = 0;
-    Line = NULL;
-    plus = &(Map->plus);
+    Area = Map->plus.Area[area];
+    if (!Area)
+	G_fatal_error(_("%s: Area %d does not exist"),
+		      "add_area_cats_to_cidx():", area);
 
-    if (plus->built >= GV_BUILD_BASE) {
-	Line = Map->plus.Line[line];
+    if (Area->centroid == 0) /* no centroid found */
+	return;
 
-	if (Line == NULL)
-	    G_fatal_error(_("Attempt to delete dead feature"));
-	type = Line->type;
-    }
-
-    if (!Cats) {
+    if (!Cats)
 	Cats = Vect_new_cats_struct();
-    }
-    if (!Points) {
-	Points = Vect_new_line_struct();
-    }
 
-    type = V2_read_line_nat(Map, Points, Cats, line);
+    V2_read_line_nat(Map, NULL, Cats, Area->centroid);
 
-    /* Update category index */
-    if (plus->update_cidx) {
-	for (i = 0; i < Cats->n_cats; i++) {
-	    dig_cidx_del_cat(plus, Cats->field[i], Cats->cat[i], line, type);
-	}
+    for (i = 0; i < Cats->n_cats; i++) {
+	dig_cidx_add_cat_sorted(&(Map->plus), Cats->field[i], Cats->cat[i],
+				area, GV_AREA);
     }
+}
 
-    /* delete the line from coor */
-    ret = V1_delete_line_nat(Map, Line->offset);
+/*!
+  \brief Delete feature from topology (internal use only)
 
-    if (ret == -1) {
-	return ret;
+  Note: This function requires build level >= GV_BUILD_BASE.
+
+  Also updates category index if requested.
+
+  Calls G_warning() on error.
+  
+  \param Map pointer to Map_info struct
+  \param line feature id to be removed
+  \param Points feature geometry (pointer to line_pnts struct)
+  \param external_routine external subroutine to execute (used by PostGIS Topology)
+
+  \return 0 on success
+  \return -1 on failure
+ */
+int V2__delete_line_from_topo_nat(struct Map_info *Map, int line, int type,
+                                  const struct line_pnts *points, const struct line_cats *cats)
+{
+    int i, first;
+    int adjacent[4], n_adjacent;
+    
+    struct bound_box box, abox;
+    struct Plus_head *plus;
+    struct P_line *Line;
+    
+    n_adjacent = 0;
+    
+    plus = &(Map->plus);
+    
+    if (line < 1 || line > plus->n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
     }
+    
+    Line = Map->plus.Line[line];
+    if (!Line) {
+        G_warning(_("Attempt to access dead feature %d"), line);
+        return -1;
+    }
 
-    /* Update topology */
-    if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
-	struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
+    /* delete feature from category index */
+    if (plus->update_cidx && cats) {
+        for (i = 0; i < cats->n_cats; i++) {
+            dig_cidx_del_cat(plus, cats->field[i], cats->cat[i], line, type);
+        }
+    }
+    
+    /* update areas when deleting boundary from topology */
+    if (plus->built >= GV_BUILD_AREAS && Line->type == GV_BOUNDARY) {
+        int next_line;
+        
+        struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
 
-	/* Store adjacent boundaries at nodes (will be used to rebuild area/isle) */
-	/* Adjacent are stored: > 0 - we want right side; < 0 - we want left side */
+	/* store adjacent boundaries at nodes (will be used to rebuild area/isle) */
+	/* adjacent are stored: > 0 - we want right side; < 0 - we want left side */
 	n_adjacent = 0;
 
 	next_line = dig_angle_next_line(plus, line, GV_RIGHT, GV_BOUNDARY, NULL);
@@ -741,7 +644,7 @@
 	    n_adjacent++;
 	}
 
-	/* Delete area(s) and islands this line forms */
+	/* delete area(s) and islands this line forms */
 	first = 1;
 	if (topo->left > 0) {	/* delete area */
 	    Vect_get_area_box(Map, topo->left, &box);
@@ -779,8 +682,10 @@
 	}
     }
 
-    /* Delete reference from area */
-    if (plus->built >= GV_BUILD_CENTROIDS && type == GV_CENTROID) {
+    /* delete reference from area */
+    if (plus->built >= GV_BUILD_CENTROIDS && Line->type == GV_CENTROID) {
+        struct P_area *Area;
+        
 	struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
 
 	if (topo->area > 0) {
@@ -792,15 +697,17 @@
 	    if (Area) 
 		Area->centroid = 0;
 	    else
-		G_warning(_("Attempt to access dead area (%d)"), topo->area);
+		G_warning(_("Attempt to access dead area %d"), topo->area);
 	}
     }
 
     /* delete the line from topo */
-    dig_del_line(plus, line, Points->x[0], Points->y[0], Points->z[0]);
-
-    /* Rebuild areas/isles and attach centroids and isles */
+    if (0 != dig_del_line(plus, line, points->x[0], points->y[0], points->z[0]))
+        return -1;
+    
+    /* rebuild areas/isles and attach centroids and isles */
     if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
+        int i, side, area;
 	int new_areas[4], nnew_areas = 0;
 
 	/* Rebuild areas/isles */
@@ -834,14 +741,14 @@
 		    Vect_box_extend(&abox, &box);
 	    }
 	}
-	/* Reattach all centroids/isles in deleted areas + new area.
-	 *  Because isles are selected by box it covers also possible new isle created above */
+	/* reattach all centroids/isles in deleted areas + new area.
+	 *  because isles are selected by box it covers also possible new isle created above */
 	if (!first) {		/* i.e. old area/isle was deleted or new one created */
-	    /* Reattach isles */
+	    /* reattach isles */
 	    if (plus->built >= GV_BUILD_ATTACH_ISLES)
 		Vect_attach_isles(Map, &abox);
 
-	    /* Reattach centroids */
+	    /* reattach centroids */
 	    if (plus->built >= GV_BUILD_CENTROIDS)
 		Vect_attach_centroids(Map, &abox);
 	}
@@ -853,128 +760,257 @@
 	}
     }
 
-    G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
-	    plus->uplist.n_upnodes);
-    
-    return ret;
+    if (plus->uplist.do_uplist) {
+        G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
+                plus->uplist.n_upnodes);
+    }
+
+    return 0;
 }
 
 /*!
-  \brief Restores feature at the given offset.
-  
-  \param Map pointer to Map_info structure
-  \param offset feature offset
-  
-  \return  0 on success
-  \return -1 on error
-*/
-int V1_restore_line_nat(struct Map_info *Map, off_t offset)
-{
-    char rhead;
-    struct gvfile *dig_fp;
-    
-    G_debug(3, "V1_restore_line_nat(), offset = %lu", (unsigned long) offset);
-    
-    dig_set_cur_port(&(Map->head.port));
-    dig_fp = &(Map->dig_fp);
-    
-    if (dig_fseek(dig_fp, offset, 0) == -1)
-	return -1;
-    
-    /* read old */
-    if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
-	return (-1);
+  \brief Add feature (line) to topology (internal use only)
 
-    /* mark as alive */
-    rhead |= 1;
-    
-    /* write new */
-    if (dig_fseek(dig_fp, offset, 0) == -1)
-	return -1;
+  Also updates category index if requested.
 
-    if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
-	return -1;
+  Update areas. Areas are modified if: 
+   
+  1) first or/and last point are existing nodes ->
+   - drop areas/islands whose boundaries are neighbour to this boundary at these nodes
+   - try build areas and islands for this boundary and neighbour boundaries going through these nodes
+
+   Question: may be by adding line created new area/isle which doesn't go through nodes of this line
+
+   <pre>
+             old         new line 
+         +----+----+                    +----+----+                 +----+----+ 
+         | A1 | A2 |  +      /      ->  | A1 |   /|   or +   \   -> | A1 | A2 | \
+         |    |    |                    |    |    |                 |    |    |
+         +----+----+                    +----+----+                 +----+----+
+           I1   I1                        I1   I1                      
+   </pre>        
+ 
+   - re-attach all centroids/isles inside new area(s)
+   - attach new isle to area outside
+
+  2) line is closed ring (node at the end is new, so it is not case above)
+    - build new area/isle
+    - check if it is island or contains island(s)
+    - re-attach all centroids/isles inside new area(s)
+    - attach new isle to area outside
     
-    if (0 != dig_fflush(dig_fp))
-	return -1;
-    
-    return 0;
-}
+    Note that 1) and 2) is done by the same code.
 
-/*!
-  \brief Restores feature at topological level (internal use only)
-  
-  \param Map pointer to Map_info structure
-  \param line feature id
-  \param offset feature offset
-  
-  \return 0 on success
-  \return -1 on error
+    \param Map pointer to Map_info structure
+    \param line feature id to be added
+    \param points pointer to line_pnts structure (feature's geometry)
+    \param cats pointer to line_cats structure (feature's categories)
+    \param external_routine pointer to external routine (used by PostGIS Topology)
+
+    \return feature id to be added
+    \return 0 nothing to do (build level must be >= GV_BUILD_BASE) 
+    \return -1 on error 
 */
-int V2_restore_line_nat(struct Map_info *Map, int line, off_t offset)
+int V2__add_line_to_topo_nat(struct Map_info *Map, off_t offset, int type,
+                             const struct line_pnts *points, const struct line_cats *cats,
+                             int restore_line,
+                             int (*external_routine) (const struct Map_info *, int))
 {
-    int i, ret, type;
-    struct P_line *Line;
+    int first, s, n, i, line;
+    int node, next_line, area, side, sel_area, new_area[2];
+
     struct Plus_head *plus;
-    struct bound_box box;
+    struct P_line *Line, *NLine;
+    struct P_node *Node;
+    struct P_area *Area;
     
-    static struct line_pnts *points = NULL;
-    static struct line_cats *cats = NULL;
-    
-    Line = NULL;
-    type = 0;
-    
-    G_debug(3, "V2_restore_line_nat(), line = %d", line);
+    struct bound_box box, abox;
 
     plus = &(Map->plus);
+    
+    G_debug(3, "V2__add_line_to_topo_nat(): offset = %ld (build level = %d)", offset, plus->built);
 
-    if (plus->built >= GV_BUILD_BASE) {
-	Line = Map->plus.Line[line];
+    if (plus->built < GV_BUILD_BASE) /* nothing to build */
+        return 0;
+    
+    /* add line to topology */
+    dig_line_box(points, &box);
+    if (restore_line > 0)
+        line = dig_restore_line(plus, restore_line, type, points, &box, offset);
+    else
+        line = dig_add_line(plus, type, points, &box, offset);
+    G_debug(3, "  line added to topo with id = %d", line);
+    
+    Line = plus->Line[line];
+    
+    /* extend map bounding box */
+    if (line == 1)
+        Vect_box_copy(&(plus->box), &box);
+    else
+        Vect_box_extend(&(plus->box), &box);
 
-	if (Line != NULL)
-	    G_fatal_error(_("Attempt to restore alive feature"));
+    /* build areas on left/right side */
+    if (plus->built >= GV_BUILD_AREAS &&
+	type == GV_BOUNDARY) {
+	struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
+	
+	/* delete neighbour areas/isles */
+	first = TRUE;
+	for (s = 0; s < 2; s++) {	/* for each node */
+	    node = (s == 0 ? topo->N1 : topo->N2);
+	    G_debug(3,
+		    "  delete neighbour areas/isles: %s node = %d",
+		    (s == 0 ? "first" : "second"), node);
+	    Node = plus->Node[node];
+	    n = 0;
+	    for (i = 0; i < Node->n_lines; i++) {
+		NLine = plus->Line[abs(Node->lines[i])];
+		if (NLine->type == GV_BOUNDARY)
+		    n++;
+	    }
+	    
+	    G_debug(3, "  number of boundaries at node = %d", n);
+	    if (n > 2) {
+		/* more than 2 boundaries at node ( >= 2 old + 1 new ) */
+		/* Line above (to the right), it is enough to check to
+		   the right, because if area/isle exists it is the
+		   same to the left */
+		if (!s)
+		    next_line =
+			dig_angle_next_line(plus, line, GV_RIGHT,
+					    GV_BOUNDARY, NULL);
+		else
+		    next_line =
+			dig_angle_next_line(plus, -line, GV_RIGHT,
+					    GV_BOUNDARY, NULL);
+		
+		if (next_line != 0) {	/* there is a boundary to the right */
+		    NLine = plus->Line[abs(next_line)];
+		    topo = (struct P_topo_b *)NLine->topo;
+		    if (next_line > 0)	/* the boundary is connected by 1. node */
+			/* we are interested just in this side (close to our line) */
+			area = topo->right;	
+		    else if (next_line < 0)	/* the boundary is connected by 2. node */
+			area = topo->left;
+		    
+		    G_debug(3, "  next_line = %d area = %d", next_line,
+			    area);
+		    if (area > 0) {	/* is area */
+			Vect_get_area_box(Map, area, &box);
+			if (first) {
+			    Vect_box_copy(&abox, &box);
+			    first = FALSE;
+			}
+			else
+			    Vect_box_extend(&abox, &box);
+			
+			if (plus->update_cidx) {
+			    V2__delete_area_cats_from_cidx_nat(Map, area);
+			}
+			dig_del_area(plus, area);
+                        if (external_routine) /* call external subroutine if defined */
+                            external_routine(Map, area);
+		    }
+		    else if (area < 0) {	/* is isle */
+			dig_del_isle(plus, -area);
+                        if (external_routine)  /* call external subroutine if defined */
+                            external_routine(Map, area);
+		    }
+		}
+	    }
+	}
+        
+	/* Build new areas/isles.
+	 * It's true that we deleted also adjacent areas/isles, but
+	 * if they form new one our boundary must participate, so
+	 * we need to build areas/isles just for our boundary */
+	for (s = 0; s < 2; s++) {
+	    side = (s == 0 ? GV_LEFT : GV_RIGHT);
+	    area = Vect_build_line_area(Map, line, side);
+	    
+	    if (area > 0) {	/* area */
+		Vect_get_area_box(Map, area, &box);
+		if (first) {
+		    Vect_box_copy(&abox, &box);
+		    first = FALSE;
+		}
+		else
+		    Vect_box_extend(&abox, &box);
+	    }
+	    else if (area < 0) {
+		/* isle -> must be attached -> add to abox */
+		Vect_get_isle_box(Map, -area, &box);
+		if (first) {
+		    Vect_box_copy(&abox, &box);
+		    first = FALSE;
+		}
+		else
+		    Vect_box_extend(&abox, &box);
+	    }
+	    new_area[s] = area;
+	}
+	/* Reattach all centroids/isles in deleted areas + new area.
+	 * Because isles are selected by box it covers also possible
+	 * new isle created above */
+	if (!first) { /* i.e. old area/isle was deleted or new one created */
+	    /* Reattach isles */
+	    if (plus->built >= GV_BUILD_ATTACH_ISLES)
+		Vect_attach_isles(Map, &abox);
+	    
+	    /* Reattach centroids */
+	    if (plus->built >= GV_BUILD_CENTROIDS)
+		Vect_attach_centroids(Map, &abox);
+	}
+	/* Add to category index */
+	if (plus->update_cidx) {
+	    for (s = 0; s < 2; s++) {
+		if (new_area[s] > 0) {
+		    V2__add_area_cats_to_cidx_nat(Map, new_area[s]);
+		}
+	    }
+	}
     }
+    
+    /* attach centroid */
+    if (plus->built >= GV_BUILD_CENTROIDS) {
+	struct P_topo_c *topo;
 
-    if (!points) {
-	points = Vect_new_line_struct();
+	if (type == GV_CENTROID) {
+	    sel_area = Vect_find_area(Map, points->x[0], points->y[0]);
+	    G_debug(3, "  new centroid %d is in area %d", line, sel_area);
+	    if (sel_area > 0) {
+		Area = plus->Area[sel_area];
+		Line = plus->Line[line];
+		topo = (struct P_topo_c *)Line->topo;
+		if (Area->centroid == 0) {	/* first centroid */
+		    G_debug(3, "  first centroid -> attach to area");
+		    Area->centroid = line;
+		    topo->area = sel_area;
+		    if (plus->update_cidx) {
+			V2__add_area_cats_to_cidx_nat(Map, sel_area);
+		    }
+		}
+		else {		/* duplicate centroid */
+		    G_debug(3,
+			    "  duplicate centroid -> do not attach to area");
+		    topo->area = -sel_area;
+		}
+	    }
+	}
     }
 
-    if (!cats) {
-	cats = Vect_new_cats_struct();
+    /* add category index */
+    if (plus->update_cidx && cats) {
+        for (i = 0; i < cats->n_cats; i++) {
+            dig_cidx_add_cat_sorted(plus, cats->field[i], cats->cat[i], line,
+                                    type);
+        }
     }
 
-    /* restore the line in coor */
-    ret = V1_restore_line_nat(Map, offset);
-
-    if (ret == -1) {
-	return ret;
+    if (plus->uplist.do_uplist) {
+        G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
+                plus->uplist.n_upnodes);
     }
     
-    /* read feature geometry */
-    type = V1_read_line_nat(Map, points, cats, offset);
-    if (type < 0) {
-	return -1;
-    }
-
-    /* update category index */
-    if (plus->update_cidx) {
-	for (i = 0; i < cats->n_cats; i++) {
-	    dig_cidx_add_cat(plus, cats->field[i], cats->cat[i], line, type);
-	}
-    }
-    
-    /* restore the line from topo */		   
-    if (plus->built >= GV_BUILD_BASE) {
-	dig_line_box(points, &box);
-	dig_restore_line(plus, line, type, points, &box, offset);
-	G_debug(3, "  line restored in topo with id = %d", line);
-	Vect_box_extend(&(plus->box), &box);
-    }
-    
-    V2__add_line_to_topo_nat(Map, line, points, cats, NULL);
-
-    G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
-	    plus->uplist.n_upnodes);
-
-    return ret;
+    return line;
 }

Modified: grass/trunk/lib/vector/Vlib/write_sfa.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_sfa.c	2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/write_sfa.c	2013-04-01 15:15:14 UTC (rev 55582)
@@ -126,7 +126,9 @@
 /*!
   \brief Rewrites feature at the given offset on level 2 (OGR/PostGIS
   interface, pseudo-topological level)
-  
+
+  Note: Topology must be built at level >= GV_BUILD_BASE
+
   \param Map pointer to Map_info structure
   \param line feature id to be rewritten
   \param type feature type (see V1_write_line_ogr() for supported types)
@@ -143,13 +145,19 @@
     G_debug(3, "V2_rewrite_line_sfa(): line=%d type=%d offset=%lu",
 	    line, type, offset);
 
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
+    }
+
 #if defined HAVE_OGR || defined HAVE_POSTGRES
     if (type != V2_read_line_sfa(Map, NULL, NULL, line)) {
 	G_warning(_("Unable to rewrite feature (incompatible feature types)"));
 	return -1;
     }
 
-    V2_delete_line_sfa(Map, line);
+    if (V2_delete_line_sfa(Map, line) != 0)
+        return -1;
 
     return V2_write_line_sfa(Map, type, points, cats);
 #else
@@ -160,6 +168,8 @@
 
 /*!
   \brief Deletes feature on level 2 (OGR/PostGIS interface)
+
+  Note: Topology must be built at level >= GV_BUILD_BASE
   
   \todo Update fidx
   
@@ -178,12 +188,17 @@
     static struct line_cats *Cats = NULL;
     static struct line_pnts *Points = NULL;
 
-    G_debug(3, "V2_delete_line_sfa(), line = %d", line);
+    G_debug(3, "V2_delete_line_sfa(): line = %d", line);
 
     type = first = 0;
     Line = NULL;
     plus = &(Map->plus);
 
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
+    }
+
     if (plus->built >= GV_BUILD_BASE) {
 	Line = Map->plus.Line[line];
 
@@ -200,7 +215,9 @@
     }
 
     type = V2_read_line_sfa(Map, Points, Cats, line);
-
+    if (type < 0)
+        return -1;
+    
     /* Update category index */
     if (plus->update_cidx) {
       for (i = 0; i < Cats->n_cats; i++) {



More information about the grass-commit mailing list